原文地址:http://www.cocos2d-iphone.org/wi ... 3._menus_and_scenes
cocos2d programming guide系列由sile(泰然翻译组)翻译本系列其他文章传送门:http://ityran.com/thread-149-1-1.html
在这节里,你将会学习到cocos2d是怎么帮助你理解场景的和怎么在场景与场景之间进行转换。转换场景是很简单的,我们只要覆盖CCMenu和相关的类就可以了,这个方法就跟创建菜单场景一样简单。
场景
cocos2d里的场景就一个可见的特殊结点扮演着其它父结点的角色。你可以用你喜欢的方式来使用它,典型的用法可能是在游戏中创建一个可玩的部分,页面场景,高分榜等等,一个场景代表着CCScene类。如果一个场景是可见的、有正在运行的动作,表示它是运行的状态。任何时间片内只能有一个场景在运行。不过可能会把一个其它的场景压入到正在运行场景的上层,那么就要终止当前的场景以运行新的场景。当把这个新压入的场景运行完后就继续运行先前的场景。或者可以这么理解,有一个全新的场景代替了其它的(自从它占用了更少的内存后变得更加完美)。压入和弹出或者代替操作直接有导演对象(CCCDirector)控制。这会找到程序托管(即AppDelegate.m文件)。在applicationDidFinishLaunching方法的底部,你会发现一行如下的代码:
[[CCDirector sharedDirector] runWithScene: [HelloWorldscene]];
它的作用是告诉导演对象开始运行被给出的场景。用来替换场景的另外一种方法,举例来说,当用户点击play按钮或者当游戏结束你想退回到主菜单时,直接调用replaceScene在导演层:
[[CCDirector sharedDirector] replaceScene: [SomeOtherScenescene]];
它的作用是终止当前场景,开始下一个。你可以等运行完后重启先前的场景通过再一次调用replaceScene。如果你仅仅想终止当前的场景,请通过pushScence方法来代替replaceScene方法,然后你可以调用popScene来终止新的场景或者继续继续旧的。但是请注意一点,在iphone里内存是有限的,所有在栈里存在的场景都是需要消耗内存的。所以要让导演对象做手头的事情,比如中止/继续当前的场景,详情请看CCDirector reference。
Fancy转换(动画转换)
CC*Transition支持很多场景之间的Fancy转换:
[[CCDirectorsharedDirector] replaceScene:[CCTransitionFadetransitionWithDuration:0.5f scene:[SomeOtherScenescene]]];
一些相同的转换:
CCTransitionFade
CCTransitionFlipAngular
CCTransitionShrinkGrow
CCTransitionMoveInB
CCTransitionMoveInT
CCTransitionMoveInL
CCTransitionMoveInR
CCTransitionFadeTR
CCTransitionFadeUp
CCTransitionFlipX
CCTransitionFlipY
CCTransitionPageTurn
CCTransitionCrossFade
查看API文档可以看到更多的转换类型。
菜单
菜单提供一种方式让用户通过按钮来与游戏进行交互。人们通过按钮来直接控制场景的转换,它们也经常被用户当作一种方便灵活的方式来控制游戏
创建一个简单的菜单实例
CCMenu *myMenu = [CCMenu menuWithItems:nil];
它是一个空的菜单里面没有任何按钮,为了让菜单有用,你将需要往里面添加一些菜单项。
这里有一些经典的菜单项:
单独的菜单项之间有着微妙的不同,但是基本上当按钮被触摸了后他们允许你选择一个被调用的目标和选择器
最简单的菜单项是创建CCMenuItemImage,选择一个指定的图片作为触摸区域里的菜单项
CCMenuItemImage *menuItem1 = [CCMenuItemImageitemFromNormalImage:@"myFirstButton.png"
selectedImage: @"myFirstButton_selected.png"
target:self
selector:@selector(doSomething:)];
itemFromNormalImage是你用来作为菜单项的图片
selectedImage是作为按钮被触控使用时的图片
target是指当菜单项被按后哪个对象需要响应。在这个例子中,当菜单被创建后self指向了这个场景
selector作为目标方法被调用
注意:这里的@selector(doSomething) 和@selector(doSomething:)是不同的(注意额外的冒号)。有冒号时,菜单项被传递给方法。这是非常有用的如果你想在方法被调用的时候传递额外的数据。你可以用菜单项tag来决定如何进行。你也许会选择MenuItemType的子类来存储额外的可以使用doSomething:的信息。一旦你创建了你的菜单项,你可以用相通的方式把事例添加到任意的CCNode。
[myMenu addChild:menuItem1];
其次,你可以一次创建几个菜单项并把它们添加到menuWithItems控制器里像下面的样子(在这个例子里,请记得nil terminate控制器)CCMenu *myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
CCMenu也提供一些方便的方法来设置你的菜单,像alignitemsVertically和alignitemsInRows:
[myMenu alignItemsVertically];
然后像下面一样把它们合并到一起
// Create some menu items
CCMenuItemImage * menuItem1 = [CCMenuItemImage itemFromNormalImage:@"myfirstbutton.png"
selectedImage: @"myfirstbutton_selected.png"
target:self
selector:@selector(doSomethingOne:)];
CCMenuItemImage * menuItem2 = [CCMenuItemImage itemFromNormalImage:@"mysecondbutton.png"
selectedImage: @"mysecondbutton_selected.png"
target:self
selector:@selector(doSomethingTwo:)];
CCMenuItemImage * menuItem3 = [CCMenuItemImage itemFromNormalImage:@"mythirdbutton.png"
selectedImage: @"mythirdbutton_selected.png"
target:self
selector:@selector(doSomethingThree:)];
// Create a menu and add your menu items to it
CCMenu * myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
// Arrange the menu items vertically
[myMenu alignItemsVertically];
// add the menu to your scene
[self addChild:myMenu];
这里有6张图片你可以用来做例子:
下载它们并把它们添加到你的工程项目中的资源文件夹里(当你把它们下载后请重新命名它们,并区分它们的大小写)
你需要注意每个菜单按照上面的方法定义后必须有单独调用它们的方法,你必须添加一些内容
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(@"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(@"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem *) menuItem
{
NSLog(@"The third menu was called");
}
想了解更多的菜单并知道如何使用它们,请 CCMenu阅读文档
在学习完了前三节后你应该知道如何做了,但是请注意必要的换行和空格
//
// HelloWorldLayer.m
// Lesson1
//
// Import the interfaces
#import "HelloWorldScene.h"
#import "CCTouchDispatcher.h"
CCSprite *seeker1;
CCSprite *cocosGuy;
// HelloWorld implementation
@implementation HelloWorld
+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorld *layer = [HelloWorld node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// set up the Menus
-(void) setUpMenus
{
// Create some menu items
CCMenuItemImage * menuItem1 = [CCMenuItemImage itemFromNormalImage:@"myfirstbutton.png"
selectedImage: @"myfirstbutton_selected.png"
target:self
selector:@selector(doSomethingOne:)];
CCMenuItemImage * menuItem2 = [CCMenuItemImage itemFromNormalImage:@"mysecondbutton.png"
selectedImage: @"mysecondbutton_selected.png"
target:self
selector:@selector(doSomethingTwo:)];
CCMenuItemImage * menuItem3 = [CCMenuItemImage itemFromNormalImage:@"mythirdbutton.png"
selectedImage: @"mythirdbutton_selected.png"
target:self
selector:@selector(doSomethingThree:)];
// Create a menu and add your menu items to it
CCMenu * myMenu = [CCMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
// Arrange the menu items vertically
[myMenu alignItemsVertically];
// add the menu to your scene
[self addChild:myMenu];
}
// 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 our seeker sprite, and add it to this layer
seeker1 = [CCSprite spriteWithFile: @"seeker.png"];
seeker1.position = ccp( 50, 100 );
[self addChild:seeker1];
// do the same for our cocos2d guy, reusing the app icon as its image
cocosGuy = [CCSprite spriteWithFile: @"Icon.png"];
cocosGuy.position = ccp( 200, 300 );
[self addChild:cocosGuy];
// schedule a repeating callback on every frame
[self schedule:@selector(nextFrame:)];
[self setUpMenus];
// register to receive targeted touch events
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
priority:0
swallowsTouches:YES];
}
return self;
}
// 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];
}
- (void) nextFrame:(ccTime)dt {
seeker1.position = ccp( seeker1.position.x + 100*dt, seeker1.position.y );
if (seeker1.position.x > 480+32) {
seeker1.position = ccp( -32, seeker1.position.y );
}
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView: [touch view]];
CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
[cocosGuy stopAllActions];
[cocosGuy runAction: [CCMoveTo actionWithDuration:1 position:convertedLocation]];
}
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(@"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(@"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem *) menuItem
{
NSLog(@"The third menu was called");
}
@end
//菜单项也可以用单独的作用域来代替选择器
// Create some menu items
CCMenuItemLabel *mi1 = [CCMenuItemLabel
itemWithLabel:someLabel
block:^(id sender) {
[theDirector pushScene:[SceneGame node];
}
];