(译)cocos2d菜单教程:第二部分
原文链接地址:http://www.iphonegametutorials.com/2010/09/07/cocos2d-menu-tutorial-part-2/
如果你还没有阅读过第一篇教程的话,那么我建议你在继续之前,回过头去完成第一部分教程再回来。
今天,我们将在上一篇教程之上添加一些东西,同时,我们会用到动画和layer之间的切换效果(transition)。
这里有本教程的完整源代码。
好了,正式出发吧!第一步,就是整理一下我们将要实现些什么东西。如果在编码之前,你不做任何的计划的话,那么你什么也做不成!下面是我们这篇教程将要实现的功能特性列表:
- 为credit场景和play场景添加一个新的层
- 当从一个场景切换到另一个场景的时候,做一些transition。
- 用文本构建菜单系统。
我保证接下来的内容很直白,而且很容易。
让我们先创建两个新类“PlayerLayer”和“CreditLayer”--为什么要有Credit Layer?好吧,其实就是让别人知道这个游戏是你做的。我真的希望“PlayLayer”很清晰明了,其实就是我们游戏的GameScene或者MainScene,就是你实际玩游戏的场景。
因此,像之前添加“SceneManger”类一样,右键点击“Classes”分组,然后选择“Add”,再选择“New Files”,确保选择“Objective-c”选项,同时要保证同时创建.h文件被勾上,如下所示:
同样的方法创建CreditsLayer:
现在,我们有两个文件,但是里面啥也没有。。。别担心,我们马上会讲到如何添加里面的内容--首先是PlayerLayer.h文件:
#import "cocos2d.h"
#import "SceneManager.h"
@interface PlayLayer : CCLayer {
}
-(void) back: (id) sender;
@end
现在是PlayerLayer.m文件:
#import "PlayLayer.h"
@implementation PlayLayer
-(id) init{
self = [super init];
if (!self) {
return nil;
}
CCMenuItemFont *back = [CCMenuItemFont itemFromString:@"back" target:self selector: @selector(back:)];
CCMenu *menu = [CCMenu menuWithItems: back, nil];
menu.position = ccp(160, 150);
[self addChild: menu];
return self;
}
-(void) back: (id) sender{
[SceneManager goMenu];
}
@end
现在,CreditsLayer和PlayerLayer几乎差不多,除了名字不同以外。但是,为了教学的需要,我还是要展示出来--首先是CreditsLayer.h文件:
#import "cocos2d.h"
#import "SceneManager.h"
@interface CreditsLayer : CCLayer {
}
-(void) back: (id) sender;
@end
然后是CreditsLayer.m文件:
#import "CreditsLayer.h"
@implementation CreditsLayer
-(id) init{
self = [super init];
if (!self) {
return nil;
}
CCMenuItemFont *back = [CCMenuItemFont itemFromString:@"back" target:self selector: @selector(back:)];
CCMenu *menu = [CCMenu menuWithItems: back, nil];
menu.position = ccp(160, 150);
[self addChild: menu];
return self;
}
-(void) back: (id) sender{
[SceneManager goMenu];
}
@end
这些文件现在都只干一件事情----有一个“back”菜单按钮,当用户点击的时候,就通过SceneManager调转到MenuLayer。然后,如果你现在编译运行的话,也不会有任何问题,但是,你点back的时候,并不会跳转到任何场景去。。。我们马上就会来解决这个问题!
现在,我们回到SceneManager并作一些修改----添加两个方法“goPlay”和“goCredits”:
#import
#import "MenuLayer.h"
#import "PlayLayer.h"
#import "CreditsLayer.h"
@interface SceneManager : NSObject {
}
+(void) goMenu;
+(void) goPlay;
+(void) goCredits;
@end
同时,我们要向SceneManager.m里面添加两个方法的实现,它让我们能够跳转到PlayerLayer和CreditsLayer中去。
+(void) goPlay{
CCLayer *layer = [PlayLayer node];
[SceneManager go: layer];
}
+(void) goCredits{
CCLayer *layer = [CreditsLayer node];
[SceneManager go: layer];
}
因此,现在完整的SceneManager.m文件,看起来如下所示:
#import "SceneManager.h"
@interface SceneManager ()
+(void) go: (CCLayer *) layer;
+(CCScene *) wrap: (CCLayer *) layer;
@end
@implementation SceneManager
+(void) goMenu{
CCLayer *layer = [MenuLayer node];
[SceneManager go: layer];
}
+(void) goPlay{
CCLayer *layer = [PlayLayer node];
[SceneManager go: layer];
}
+(void) goCredits{
CCLayer *layer = [CreditsLayer node];
[SceneManager go: layer];
}
+(void) go: (CCLayer *) layer{
CCDirector *director = [CCDirector sharedDirector];
CCScene *newScene = [SceneManager wrap:layer];
if ([director runningScene]) {
[director replaceScene:newScene];
}else {
[director runWithScene:newScene];
}
}
+(CCScene *) wrap: (CCLayer *) layer{
CCScene *newScene = [CCScene node];
[newScene addChild: layer];
return newScene;
}
@end
现在,我们只需要在MenuLayer中添加一些调用就可以了!
首先,修改MenuLayer的头文件:
#import "cocos2d.h"
#import "SceneManager.h"
#import "PlayLayer.h"
#import "CreditsLayer.h"
@interface MenuLayer : CCLayer {
}
- (void)onNewGame:(id)sender;
- (void)onCredits:(id)sender;
@end
因为,我们创建了“onNewGame”和“onCredits”两个函数,在第一部分里,我们并没有在MenuLayer.h里添加任何方法声明。当然,不要忘了#imports PlayerLayer.h和CreditsLayer.h两个头文件。
最后,我们需要在MenuLayer.m文件里使用SceneManager来实现“onNewGame”和“onCredits”两个方法:
- (void)onNewGame:(id)sender{
[SceneManager goPlay];
}
- (void)onCredits:(id)sender{
[SceneManager goCredits];
}
哇!就这么多代码!现在编译并运行,你现在有一个菜单,可以从“Play”到“Menu”,以及“Credits”之间相互切换了。
但是,看起来有点生硬,不够生动---接下来,让我们做一些更有趣的事情吧---来玩一玩transitons怎么样?:)
———————–
New Note
在2010年9月1日,cocos2d更新到0.99.5-beta2了,在Transition方面做了一此改变。一些名字被改动了,如果你之前使用的是0.99.4,如果更新到0.99.5的话,那么会有一些错误。
下面是你需要做的一些更改,如果你是从0.99.4更新到0.99.5的话:
Transitions
所有的Transition类都被重新命名了
Old New
CCXXXTransition CCTransitionXXX
Example:
Old New
CCFadeTransition CCTransitionFade
你可以从下面的链接看到完整的更改列表:
http://www.cocos2d-iphone.org/wiki/doku.php/release_notes:0_99_5
———————–
那么,我们怎么做呢?我们可以让SceneManager来完成所有的工作。好,我们先在“go”方法里面使用CCFadeTransition来replaceScene,如下所示:
[director replaceScene:[CCFadeTransition transitionWithDuration:1.2f scene:newScene withColor:ccWHITE]];
从下载下来的cocos2d 测试代码中,找到Transition.h/.m,那里面有所有的transition的用法:
以下是一些样例:
[CCFadeTransition transitionWithDuration:1.2 scene:newScene withColor:ccWHITE];
[CCZoomFlipXTransition transitionWithDuration:1.2 scene:newScene orientation:kOrientationLeftOver];
[CCFlipYTransition transitionWithDuration:1.2 scene:newScene orientation:kOrientationDownOver];
我们将封装一下我们的类,使之接收两个参数“delay time”和“new scene”的名字。。。为了从场景的字符串名字获得场景类,我们所要下面这个方法:
Class c = NSClassFromString(r);"
整个SceneManager类看起来如下所示:
#define TRANSITION_DURATION (1.2f)
@interface FadeWhiteTransition : CCFadeTransition
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s;
@end
@interface ZoomFlipXLeftOver : CCZoomFlipXTransition
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s;
@end
@interface FlipYDownOver : CCFlipYTransition
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s;
@end
@implementation FadeWhiteTransition
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s {
return [self transitionWithDuration:t scene:s withColor:ccWHITE];
}
@end
@implementation ZoomFlipXLeftOver
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s {
return [self transitionWithDuration:t scene:s orientation:kOrientationLeftOver];
}
@implementation FlipYDownOver
+(id) transitionWithDuration:(ccTime) t scene:(CCScene*)s {
return [self transitionWithDuration:t scene:s orientation:kOrientationDownOver];
}
staticint sceneIdx=0;
static NSString *transitions[] = {
@"FlipYDownOver",
@"FadeWhiteTransition",
@"ZoomFlipXLeftOver",
};
Class nextTransition()
{
// HACK: else NSClassFromString will fail
[CCRadialCCWTransition node];
sceneIdx++;
sceneIdx = sceneIdx % ( sizeof(transitions) /sizeof(transitions[0]) );
NSString *r = transitions[sceneIdx];
Class c = NSClassFromString(r);
return c;
}
因此,最后修改一下“go”函数,首先,我们添加下面一行代码:
Class transition = nextTransition();
然后,我们把下面的语句:
[director runWithScene:newScene];
替换成:
[director replaceScene:[transition transitionWithDuration:TRANSITION_DURATION scene:newScene]];
最终SceneManger的go函数看起来如下所示:
+(void) go: (CCLayer *) layer{
CCDirector *director = [CCDirector sharedDirector];
CCScene *newScene = [SceneManager wrap:layer];
Class transition = nextTransition();
if ([director runningScene]) {
[director replaceScene:[transition transitionWithDuration:TRANSITION_DURATION scene:newScene]];
}else {
[director runWithScene:newScene];
}
}
很酷,对吧?
好像这个教程还不够,我们还可以调加更多的效果。。。最后,我还想在菜单文本上面添加一些效果。为了实现这个,我们需要修改MenuLayer.m文件。
首先,我们先把titleLeft和titleRight CClabel从下面的代码:
titleLeft.position = ccp(80, 345);
[self addChild: titleLeft];
titleRight.position = ccp(220, 345);
[self addChild: titleRight];
改在下面的代码:
titleLeft.position = ccp(80, -80);
[self addChild: titleLeft];
titleRight.position = ccp(220, 520);
[self addChild: titleRight];
然后为每一个菜单项添加一个动画:
CCAction *titleRightAction = [CCSequence actions:
[CCDelayTime actionWithDuration: delayTime],
[CCEaseBackOut actionWithAction:
[CCMoveTo actionWithDuration: 1.0 position:ccp(220,345)]],nil];
oh!我的天,这在干嘛啊!
创建一个CCAction对象,它由于系列的事件组成。
这个事件序列首先等待0.3秒,然后移动到(220,345)的位置,时间间隔为1秒,同时用EaseBackOut修饰了,所以是先快后慢。
一旦我们创建了这个动作序列之后,我们在titleLeft上面运行这个action。
[titleLeft runAction: titleLeftAction];
我们同时要为titleRight添加类似的行为。
最后的动画就是Menu本身:
for (CCMenuItemFont *each in [menu children]) {
each.scaleX =0.0f;
each.scaleY =0.0f;
CCAction *action = [CCSequence actions:
[CCDelayTime actionWithDuration: delayTime],
[CCScaleTo actionWithDuration:0.5F scale:1.0],
nil];
delayTime +=0.2f;
[each runAction: action];
}
你可以讲讲上面的代码是干嘛用的吗?我们又创建了一个“Action”变量,先停0.3秒,然后0.5秒缩放到1.0。因为我们开始之前把scale设置为0,这样就可以在0.5秒的时间内,慢慢放大到100%的尺寸。让我们运行一下代码,体验一下吧!
再见!
著作权声明:本文由http://www.cnblogs.com/andyque翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!