(译)cocos2d菜单教程:第二部分

原文链接地址:http://www.iphonegametutorials.com/2010/09/07/cocos2d-menu-tutorial-part-2/

 

  如果你还没有阅读过第一篇教程的话,那么我建议你在继续之前,回过头去完成第一部分教程再回来。

  今天,我们将在上一篇教程之上添加一些东西,同时,我们会用到动画和layer之间的切换效果(transition)。

  这里有本教程的完整源代码

  好了,正式出发吧!第一步,就是整理一下我们将要实现些什么东西。如果在编码之前,你不做任何的计划的话,那么你什么也做不成!下面是我们这篇教程将要实现的功能特性列表:

  1. 为credit场景和play场景添加一个新的层
  2. 当从一个场景切换到另一个场景的时候,做一些transition。
  3. 用文本构建菜单系统。

  我保证接下来的内容很直白,而且很容易。

  让我们先创建两个新类“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翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

posted on 2011-07-15 21:55  子龙山人  阅读(6839)  评论(8编辑  收藏  举报