cocos2d拥有很完美的菜单管理和场景切换类,你可以使用它们为你的游戏加入菜单,完成场景之间的切换。
这次我会简单的介绍一下如何使用cocos2d提供的类库为游戏加入漂亮的菜单场景。在这一课你将会接触到菜单项的处理和场景的切换等相关知识。我不会讲述大篇幅的技术理论,我认为太多的理论对于一个初学者不仅没有帮助,反而会让他失去学习的乐趣。个人认为从实例代码下手更好,经过多次的实践之后,让读者自己去参悟其中的理论会更有效。
抛开题外话,让我们继续本章的主题。首先,让我们来创建我们的菜单类,这个类将包含两个部分,菜单场景类和菜单层类。因此我们在工程classes文件中建立一个New Group来存放管理他们会更方便。右击classes类文件夹,在弹出的菜单项中选择Add─>New Group创建一个新的Group,并将他命名为Menu。然后右击Menu文件夹,在弹出的菜单项中选择Add─>New File依次创建两个基于CCLayer的类文件,分别将它们命名为MenuScene和MenuLayer。这时你的Menu文件夹下应该有4个文件,分别是:MenuScene.h,MenuScene.h ,MenuLayer.h和MenuLayer.m文件。下面直接贴代码了:
MenuScene.h中的代码如下:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface MenuScene : CCLayer {
}
+(id) scene;
@end
MenuScene.m中的代码如下:
#import "MenuScene.h"
#import "MenuLayer.h"
@implementation MenuScene
// 实例化本场景
+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
MenuScene *layer = [MenuScene node];
[scene addChild: layer];
return scene;
}
// 初始化函数
- (id) init
{
self = [super init];
if (self)
{
// 设定菜单背景
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *bg = [CCSprite spriteWithFile:@"MenuBackground.png"];
bg.position = ccp(winSize.width / 2, winSize.height / 2);
[self addChild:bg];
// 添加菜单层
[self addChild:[MenuLayer node]];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface MenuLayer : CCLayer {
}
// 下面声明的三个方法是菜单的三个选项,开始游戏,分数和关于
- (void) startGame: (id)sender;
- (void) scores: (id)sender;
- (void) onAbout: (id)sender;
@end
#import "HelloWorldScene.h"
#import "MenuLayer.h"
#import "ScoreScene.h"
#import "AboutScene.h"
@implementation MenuLayer
// on "init" you need to initialize your instance
- (id) init
{
self = [super init];
if (self)
{
// 设定菜单文字
[CCMenuItemFont setFontName:@"Helvetica"];
[CCMenuItemFont setFontSize:30];
CCMenuItem *start = [CCMenuItemFont itemFromString:@"Start Game"
target:self
selector:@selector(startGame:)];
CCMenuItem *scores = [CCMenuItemFont itemFromString:@"Scores"
target:self
selector:@selector(scores:)];
CCMenuItem *abouts = [CCMenuItemFont itemFromString:@"About"
target:self
selector:@selector(onAbout:)];
CCMenu *menu = [CCMenu menuWithItems:start, scores, abouts, nil];
[menu alignItemsVertically];
// 菜单特效可有可无,实现一个菜单飞出式效果
CGSize s = [[CCDirector sharedDirector] winSize];
int i=0;
for( CCNode *child in [menu children] ) {
CGPoint dstPoint = child.position;
int offset = s.width/2 + 50;
if( i % 2 == 0)
offset = -offset;
child.position = ccp( dstPoint.x + offset, dstPoint.y);
[child runAction:[CCEaseElasticOut actionWithAction:[CCMoveBy actionWithDuration:2 position:ccp(dstPoint.x- offset,0)]period: 0.35f]];
i++;
}
[self addChild:menu];
}
return self;
}
// 实现菜单方法
// 切换到StartGame场景
- (void) startGame: (id)sender
{
CCScene *sc = [CCScene node];
[sc addChild:[HelloWorld node]];
// 缩放的形式切换场景
[[CCDirector sharedDirector] replaceScene: [CCShrinkGrowTransition transitionWithDuration:1.2f scene:sc]];
}
// 切换到Scores场景
- (void) scores: (id)sender
{
CCScene *sc = [CCScene node];
[sc addChild:[ScoreScene node]];
// 缩放的形式切换场景
[[CCDirector sharedDirector] replaceScene: [CCShrinkGrowTransition transitionWithDuration:1.2f scene:sc]];
}
// 切换到About场景
- (void) onAbout: (id)sender
{
CCScene *sc = [CCScene node];
[sc addChild:[AboutScene node]];
// 缩放的形式切换场景
[[CCDirector sharedDirector] replaceScene: [CCShrinkGrowTransition transitionWithDuration:1.2f scene:sc]];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
@end
到这里菜单类的编写就结束了,这里运用了场景和层分离的概念。将菜单场景与菜单层分开实现,这样可以使代码更加的清晰,层次更加分明。但是现在你还无法成功的运行你的程序,因为还有菜单项没用实现。另外你还没有修改Delegate.m托管文件中首场景载入函数的参数,你需要让它指向你编写的菜单场景。下面我们就来完成剩下的工作。首先,用同样的方法在classes文件夹下创建名为MenuOption的组,并在其下创建两个基于CCLayer的类文件,分别命名为AboutScene和ScoreScene。然后打开Delegate.m托管文件,将头文件"HelloWorldScene.h"改为"MenuScene.h"。再在- (void) applicationDidFinishLaunching:(UIApplication*)application 方法的最后一行找到 [[CCDirector sharedDirector] runWithScene: [HelloWorld scene]]; 这段函数调用,将参数中的HelloWorld改为刚创建的MenuScene场景。下面贴出菜单项类的代码:
HelloWorldScene.h中的代码如下:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
// HelloWorld Layer
@interface HelloWorld : CCLayer {
}
@end
HelloWorldScene.m中的代码如下:
#import "HelloWorldScene.h"
#import "MenuScene.h"
// HelloWorld implementation
@implementation HelloWorld
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
// create and initialize a Label
CCLabel* label = [CCLabel labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
// ask director the the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
label.position = ccp( size.width /2 , size.height/2 );
// add the label as a child to this Layer
[self addChild: label];
// 添加图形返回菜单
CCSprite *menuNormal = [CCSprite spriteWithFile:@"b_back.png" rect:CGRectMake(0, 0, 78, 41)];
CCSprite *menuSelected = [CCSprite spriteWithFile:@"b_back_s.png" rect:CGRectMake(0, 0, 78, 41)];
CCMenuItemSprite *backToMenu = [CCMenuItemSprite itemFromNormalSprite:menuNormalselectedSprite:menuSelected target:self selector:@selector(onBack:)];
CCMenu *menu = [CCMenu menuWithItems: backToMenu, nil];
[menu setPosition:ccp(480 - 50, 320 - 30)];
[self addChild: menu];
}
return self;
}
// 返回菜单方法
-(void) onBack: (id) sender
{
CCScene *sc = [CCScene node];
[sc addChild:[MenuScene node]];
[[CCDirector sharedDirector] replaceScene: [CCSlideInRTransition transitionWithDuration:1.2f scene:sc]];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
@end
AboutScene.h中的代码如下:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface AboutScene : CCLayer {
}
@end
#import "AboutScene.h"
#import "MenuScene.h"
@implementation AboutScene
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init] )) {
// 用Label显示作者
CCLabel* label = [CCLabel labelWithString:@"作者:谢映宇" fontName:@"Marker Felt" fontSize:40];
CGSize size = [[CCDirector sharedDirector] winSize];
label.position = ccp( size.width /2 , size.height/2 );
[self addChild: label];
// 添加返回菜单
[CCMenuItemFont setFontSize:20];
CCMenuItem *backToMenu = [CCMenuItemFont itemFromString:@"Back" target:selfselector:@selector(onBack:)];
CCMenu *mn = [CCMenu menuWithItems:backToMenu, nil];
[mn alignItemsVertically];
mn.position = ccp (480 - 50, 30);
[self addChild:mn z:1 tag:2];
}
return self;
}
// 返回菜单方法
-(void) onBack: (id) sender
{
CCScene *sc = [CCScene node];
[sc addChild:[MenuScene node]];
[[CCDirector sharedDirector] replaceScene: [CCSlideInRTransition transitionWithDuration:1.2f scene:sc]];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface ScoreScene : CCLayer {
}
@end
#import "ScoreScene.h"
#import "MenuScene.h"
@implementation ScoreScene
// on "init" you need to initialize your instance
-(id) init
{
if( (self=[super init] )) {
// 用Label显示分数
CCLabel* label = [CCLabel labelWithString:@"最高分:9999" fontName:@"Marker Felt" fontSize:40];
CGSize size = [[CCDirector sharedDirector] winSize];
label.position = ccp( size.width /2 , size.height/2 );
[self addChild: label];
// 添加返回菜单
[CCMenuItemFont setFontSize:20];
CCMenuItem *backToMenu = [CCMenuItemFont itemFromString:@"Back" target:selfselector:@selector(onBack:)];
CCMenu *mn = [CCMenu menuWithItems:backToMenu, nil];
[mn alignItemsVertically];
mn.position = ccp (480 - 50, 30);
[self addChild:mn z:1 tag:2];
}
return self;
}
// 返回菜单方法
-(void) onBack: (id) sender
{
CCScene *sc = [CCScene node];
[sc addChild:[MenuScene node]];
[[CCDirector sharedDirector] replaceScene: [CCSlideInRTransition transitionWithDuration:1.2f scene:sc]];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
@end