3.【cocos2d翻译系列】Beginner's Guide-Lesson3:Scene and menus

来源:互联网 发布:服务器网络拓扑图 编辑:程序博客网 时间:2024/05/16 07:25

Lesson3:Scene and menus(场景和菜单)

在这篇教程中,你将会学习怎样使用"scenes"来安排(划分场景)你的游戏,并且怎样在scene和scene之间转换。

这些东西比较简单,我们也会涉及CCMenu及相关的一些类,用这些可以很简单地创建菜单scene。

这篇教程假设你已经学习过了Lesson1.Install & Test 和 Lesson2.Your First Game


  • Scenes(场景)

    Cocos2d中的"scene"就是指定类型的node(CCNode的子类),它可以作为基本的父容器用来盛放其他可见的node。

你可以根据你的喜好使用它,但是典型的用法一般是用一个scene作为你真正游戏的场景,用另一个scene显示游戏标题,

最高分列表,选项,等等。用CCScene类来描述一个scene。


    一个scene如果是可见的那么说明它正在运行,可以执行actions等等。在同一时刻只能有一个scene运行。然而有时,

可能需要运行另一个scene,那就暂停当前的scene;过后在恢复当前的scene。(原文说得比较麻烦:将另一个新的

scene入栈,它就会在原来那个scene的上面,然后暂停当前的scene,运行新的scene,过后在将运行的scene出栈,

恢复运行原来的那个scene)或者,你可以使用一个scene替代全部其他的scene(这种方法不错,因为它占用的内存更少)

这种入栈/出栈或者替换scene的事情都是由导演(CCDirector)做的。如果你浏览过工程模板的话,你应该见过入下得代

码。在应用代理appDelegate中(例如:在Lesson2AppDelegate.m或者其他类似的文件名)的函数

applicationDidFinishLaunching的末尾处,你将会发现如下的代码:

[[CCDirector sharedDirector] runWithScene: [HelloWorld scene]];

这行代码就是告诉导演开始运行给定的scene(HelloWorld)

用其他的scene替换当前正在运行的scene(例如:当用户点屏幕上的菜单“Play”按钮时,或者当游戏结束后你想回到主菜单时)

只需要调用导演的replaceScene函数:

[[CCDirector sharedDirector] replaceScene: [SomeOtherScene scene]];

这行代码就是结束当前的scene,并且运行指定的scene。你也可以通过再次调用replaceScene,重新运行原来的那个scene。

如果你仅仅是想暂时停止当前的scene,使用pushScene代替replaceScene。随后你可以通过调用popScene结束新的scene,

恢复原来的那个scene。但是要尽量少使用,因为iPhone的内存容量是有限的,并且所有的scene的堆栈都是在内存中的。

导演还能做许多事,像暂停/恢复当前的scene 。想要详细了解CCDirector 去官方网站查看CCDirector reference


  • Fancy Transitions (转场特效)

场景和场景之间的转场特效支持由CCTransition*类支持

[[CCDirector sharedDirector] replaceScene: [CCTransitionFade transitionWithDuration:0.5f                                                              scene:[SomeOhterScene scene]];  

一些常用的转场类:

  • CCTransitionFade (逐渐变淡)
  • CCTransitionFlipAngular  (对角立体旋转)
  • CCTransitionShrinkGrow (缩放效果)
  • CCTransitionMoveInB  (从下方出现)
  • CCTransitionMoveInT  (从上方出现)
  • CCTransitionMoveInL  (从左边出现)
  • CCTransitionMoveInR  (从右方出现)
  • CCTransitionFadeTR  (从左下方向右上方碎片化变淡)
  • CCTransitionFadeUp  (从下向上横栏翻转式变淡)
  • CCTransitionFlipX  (左右立体翻转)
  • CCTransitionFlipY  (上下立体翻转)
  • CCTransitionPageTurn  (翻页效果)
  • CCTransitionCrossFade  (逐渐变淡)

想知道更多地转场类可以查看API文档


  • Menu

菜单提供了一条用户和游戏交互的途径,这里使用了一个GUI(图形用户界面)概念:“按钮”。人们常常通过菜单告诉导演

切换scene,但是菜单也是一种方便灵活的控制游戏的方法。

创建菜单,仅需创建一个CCMenu的实例:

CCMenu * myMenu = [CCMenu menuWithItems:nil];
这段代码创建一个空的菜单,没有菜单项(按钮)。为了使菜单能用,你需要添加一些菜单项。这里有几种菜单项可供选择:
  • CCMenuItemAtlasFont
  • CCMenuItemFont
  • CCMenuItemImage
  • CCMenuItemLabel
  • CCMenuItemSprite
  • CCMenuItemToggle 

    这些菜单项之间有细微的不同,但是从本质来说,它们都允许你指定一个目标对象(target)和一个selector

(当按钮被触摸的时候会调用)。

    其中最简单的一个创建菜单项的方法就是用CCMenuItemImage,只需使用一个指定的图片作为菜单项的“触摸区域”。

CCMenuItemImage *menuItem1 = [CCMenuItemImage itemFromNormalImage:@"myFirstButton.png"                  selectedImage: @"myFirstButton_selected.png"                   target:self                   selector:@selector(doSomething:)];
  • itemFromNormalImage就是你想当做菜单项的图片
  • selectedImage就是当按钮被触摸时的按钮图片
  • target指定了哪个对象处理菜单项的触摸事件(此处使用self,代表了菜单所处的那个scene
  • selector就是要被调用的目标函数

注意:@selector(doSomething)和@selector(doSomething:)是不一样的(注意那个多出来的冒号)。带着那个冒号,这个菜单项

会作为参数传递过去。这个函数被调用时,你给它传过去这个附加的数据是非常有用的。例如,你可以使用菜单项的'tag'属性决定

怎样开始。你甚至可以选择用子类扩充添加一些额外的信息,然后在被调用的函数中访问。

一旦你创建了你的菜单项,你可以添加它们到菜单中,添加的方法和添加“东西”到CCNode中是一样的。

[myMenu addChild:menuItem1];

 二选一就行,你还可以一次性创建几个菜单项并且添加它们到菜单中,用那个创建菜单时用到的函数menuWithItem构造函数,

就像这样。。。(在这个例子中,记住一点构造函数参数列表要以nil结尾)

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(添加菜单到你的scene中)[self addChild:myMenu];

这里有6个图片供你测试显示的结果

为了使用这些图片你需要下载它们,并且把它们放在你工程得根目录下,然后添加它们到你Xcode中的资源文件夹中。

你会注意到每一个菜单项都有一个单独的回调函数,所以你需要添加上它们:

- (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"); } 

 

查询更多关于menus的用法,请通读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

菜单项也可以使用block语法替代selector语法 

// Create some menu itemsCCMenuItemLabel *mi1 = [CCMenuItemLabel itemWithLabel:someLabel block:^(id sender) {  [theDirector pushScene:[SceneGame node];} ]; 

你可以在这里找到Objective-C的blocks语法。Blocks语法帮助消除那些只使用一次的函数。

原创粉丝点击