(译)在cocos2d里面如何制做按钮:简单按钮、单选按钮和开关按钮

 免责申明(必读!):本博客提供的全部教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客全部人、发表该翻译稿之人无任何关系。谢谢合做! php

原文连接地址:http://www.raywenderlich.com/414/how-to-create-buttons-in-cocos2d-simple-radio-and-toggle html

程序截图: app

  当你在使用cocos2d制做一个游戏的时候,你极可能会发现,你须要的第一个东西就是“按钮”。(好比游戏开始时的菜单选择界面等)这个教程将会一步步地教你如何使用cocos2d来建立按钮。刚开始建立简单的按钮,而后再介绍开关按钮和单选按钮。这篇教程假设你已经阅读了《如何使用cocos2d来制做简单的iphone游戏》这一系列的教程,或者具有同等相关经验。 iphone

  当我第一次想要在cocos2d里面添加一个按钮的时候,我是这样想的:建立一个精灵(sprite)来表明按钮,而后检测这个按钮何时被按下去。固然,这样作确定是可行的。可是,在cocos2d里面,还有更简单的方法--经过使用cocos2d的菜单系统。 ide

  在cocos2d的菜单系统里面,包含一个menu,在menu里面又包含一系列的menuitems。Menu items能够是文本或者图片,并且菜单系统里面还包含了一些很是有用的逻辑,好比:排列菜单项(menu item),高亮显示被按下去的菜单项,开关菜单项等等。好了,让咱们实践一下,看看用cocos2d的方式如何建立一个简单的按钮! 函数

建立一个简单的按钮

  打开Xcode,使用cocos2d Application template建立一个新的工程并命名为:CCButtons。接下来,你须要一些按钮的图片--你能够本身建立,或者下载一些我已经作好的图片。好了,如今你有图片了,把它们拖到resource文件夹下面,同时确保选中“ Copy items into destination group’s folder (if needed)”。 布局

  打开Classes分组下面的HelloWorldscene.h文件,而后在HelloWorld类里面添加一个成员变量,后面将会用到它: 学习

CCLabelTTF  * _label;

  而后,为了防止忘记内存清理操做,打开HelloWorldScene.m并在dealloc方法中添加一些清理的代码: ui

 

[_label release];
_label 
=  nil;

  好了,接下来就是重点了。一样,在HelloWorldScene.m文件中,用下面的代码替换掉init方法: google

复制代码
- (id) init
{
if ( (self = [super init] )) {

CGSize winSize 
=  [[CCDirector sharedDirector] winSize];

//  Create a label for display purposes
_label  =  [[CCLabelTTF labelWithString: @" Last button: None "  
dimensions:CGSizeMake(
320 50 ) alignment:UITextAlignmentCenter 
fontName:
@" Arial "  fontSize: 32.0 ] retain];
_label.position 
=  ccp(winSize.width / 2
winSize.height
- (_label.contentSize.height / 2 ));
[self addChild:_label];

//  Standard method to create a button
CCMenuItem  * starMenuItem  =  [CCMenuItemImage 
itemFromNormalImage:
@" ButtonStar.png "  selectedImage: @" ButtonStarSel.png "  
target:self selector:@selector(starButtonTapped:)];
starMenuItem.position 
=  ccp( 60 60 );
CCMenu 
* starMenu  =  [CCMenu menuWithItems:starMenuItem, nil];
starMenu.position 
=  CGPointZero;
[self addChild:starMenu];

}
return  self;
}
复制代码

  首先,为了调试方便,咱们建立了一个label。这个看起来很熟悉对不对?---咱们在上一篇教程中有提到过。然而,这一次咱们使用了一个新的构造函数,它可让咱们指定label的大小和文字对齐方式。在这里,我把label的大小设置和窗口大小同样宽,并且文本须要居中对齐。这是一种广为人知的技术了,特别是当你想实现一些左对齐或者右对齐的文本的时候。

  接下来的代码是建立按钮。首先使用类CCMenuItemImage来建立一个菜单项,并为这个按钮指定一张被选中的图片和没有被选中的图片。(也就是单击时被显示的图片和没有被单击时被显示的图片)当建立完菜单项以后,咱们为按钮的点击事件指定了一个回调函数(这个函数后面会给出代码)。最后一步,就是建立一个菜单来包含这个按钮(或者一系列的按钮,以nil结尾)。

  注意,咱们在CGPointZero(原点)的位置建立了按钮。这里实际上指定了菜单的中心点的位置。而后,咱们指定菜单项的位置相对于菜单的位置偏移(60,60)--这样的话,在屏幕上面显示的时候,菜单项就会显示在(60,60)的位置了。(由于菜单项的position是相对于菜单的中心点来的,把菜单的中心点设置为(0,0),与屏幕坐标原点重合后,能够方便为每一个菜单项指定坐标点,由于这时候,只要按钮实际屏幕出现的位置设置菜单项的坐标点就好了)。

  好了,还有一些代码须要补充。在init方法后面,添加咱们的按钮回调函数:

-  ( void )starButtonTapped:(id)sender {
[_label setString:
@" Last button: * " ];
}

  编译并运行,你会看到以下的运行结果:

开关按钮

  另一种在iphone游戏里面经常使用的按钮类型就是--开关按钮。这种类型的按钮一次只有一个图片显示出来,当你单击它的时候,它就会切换到另一张图片。这个能够用来制做一个控制面板的可见性的控制器,这样能够最大限度地利用iphone上面有限的屏幕大小。

  很是幸运的是,cocos2d里面就内置了一种特殊的menu item叫作CCMenuItemToggle,它可使事情变得更加简单。让咱们来体验一下吧!首先,在HelloWorldScene.h里面添加2个成员变量:

CCMenuItem  * _plusItem; 
CCMenuItem 
* _minusItem;

  而后在dealloc方法里面添加下面的清理代码:

[_plusItem release];
_plusItem 
=  nil;
[_minusItem release];
_minusItem 
=  nil;

  而后,在你为场景添加的StartMenu后面,再添加下面的代码:

复制代码
_plusItem  =  [[CCMenuItemImage itemFromNormalImage: @" ButtonPlus.png "  
selectedImage:
@" ButtonPlusSel.png "  target:nil selector:nil] retain];
_minusItem 
=  [[CCMenuItemImage itemFromNormalImage: @" ButtonMinus.png "  
selectedImage:
@" ButtonMinusSel.png "  target:nil selector:nil] retain];
CCMenuItemToggle 
* toggleItem  =  [CCMenuItemToggle itemWithTarget:self 
selector:@selector(plusMinusButtonTapped:) items:_plusItem, _minusItem, nil];
CCMenu 
* toggleMenu  =  [CCMenu menuWithItems:toggleItem, nil];
toggleMenu.position 
=  ccp( 60 120 );
[self addChild:toggleMenu];
复制代码

  首先,  就像咱们前一个例子中同样,建立两个CCMenuItemImage。这里有一点不一样--我把它们都添加到了CCMenuItemToggle里面。这个类会管理当前应该显示的菜单项,同时会在开关元素之间进行一些切换。

  注意,当建立CCMenuItemImage的时候,我把回调函数设置成了nil,可是我为CCMenuItemToggle类设置了回调函数。这样,就会使得代码意途更加清晰:当CCMenuItemImage在CCMenuItemToggle中的时候,在CCMenuItemImage上的任何selector都不会被调用,而只有 CCMenuItemToggle的selector会被调用。固然,咱们能够很容易地在回调函数里面区分,到底哪一个菜单项是可见的。

  接下来,让咱们看看如何实现回调函数吧!在init方法后面添加下面的代码:

复制代码
-  ( void )plusMinusButtonTapped:(id)sender { 
CCMenuItemToggle 
* toggleItem  =  (CCMenuItemToggle  * )sender;
if  (toggleItem.selectedItem  ==  _plusItem) {
[_label setString:
@" Visible button: + " ]; 
else if  (toggleItem.selectedItem  ==  _minusItem) {
[_label setString:
@" Visible button: - " ];

}
复制代码

  所以,正如你所见,CCMenuItemToggle里有一个selectedItem属性,它能够告诉咱们它的哪个子菜单项当前可见(注意,当前可见的不等于被单击的)

  好了,让咱们运行一下吧!你会看到以下结果:

单选按钮

  第三种经常使用的按钮类型就是单选按钮(radio button).我在作一个游戏的时候,发现本身须要一些单选按钮,可是,cocos2d的源代码里面并无任何有关单选按钮的实现。所以,咱们本身实现一个单选按钮。而后,当我在写这篇教程的时候,我发现另外两我的也写了一些《在cocos2d里面如何支持单选按钮》的文章--这意味着,在不久的未来,你将会在cocos2d的源文件里面看到有关单选按钮的实现。

  可是,目前cocos2d里面仍是没有,所以,在这期间,你能够免费地使用我上面提到的一些实现。这篇教程使用的是我本身写的单选按钮的实现。首先,下载CCRadioMenu.h和CCRadioMenu.m,而后把它们拖到你的Classes分组下面(确保复选“”)。而后在HelloWorldScene.m的顶部添加下面代码:

#import  " CCRadioMenu.h "

  而后,在init方法后面,紧跟你添加开关按钮的代码,添加下面代码:

复制代码
CCMenuItem  * menuItem1  =  [CCMenuItemImage itemFromNormalImage: @" Button1.png "  
selectedImage:
@" Button1Sel.png "  target:self selector:@selector(button1Tapped:)];
CCMenuItem 
* menuItem2  =  [CCMenuItemImage itemFromNormalImage: @" Button2.png "  
selectedImage:
@" Button2Sel.png "  target:self selector:@selector(button2Tapped:)];
CCMenuItem 
* menuItem3  =  [CCMenuItemImage itemFromNormalImage: @" Button3.png "  
selectedImage:
@" Button3Sel.png "  target:self selector:@selector(button3Tapped:)];
CCRadioMenu 
* radioMenu  =  
[CCRadioMenu menuWithItems:menuItem1, menuItem2, menuItem3, nil];
radioMenu.position 
=  ccp( 120 180 );
[radioMenu alignItemsHorizontally];
radioMenu.selectedItem 
=  menuItem1;
[menuItem1 selected];
[self addChild:radioMenu];
复制代码

  首先,像以前同样,建立CCMenuItemImage,可是咱们不是把它加到CCMenu类中,而是把它们加到CCRadioMenu类中。这个类确保一次只有一个菜单项被选中。这里,咱们设置默认状况下,第一个菜单项被选中。

  这里有一个新的知识点:咱们利用cocos2d里面的本身布局功能,调用menu的alignItemsHorizontally来水平对齐menu中的全部菜单项。注意,菜单项是相对于菜单的中心点来布局的。所以,咱们再也不须要把菜单的中心点设置为(0,0)了--取而代之的是,咱们须要把菜单往中间靠右挪动一些,这样咱们就可让菜单项都完整地显示出来。

  最后一件事情--像以前同样添加回调函数:

复制代码
-  ( void )button1Tapped:(id)sender {
[_label setString:
@" Last button: 1 " ];
}

-  ( void )button2Tapped:(id)sender {
[_label setString:
@" Last button: 2 " ];
}

-  ( void )button3Tapped:(id)sender {
[_label setString:
@" Last button: 3 " ];
}
复制代码

 

编译并运行,你将会看到下面的结果:

背后的原理

  若是你看一看菜单系统是如何实现的,你会注意到全部的菜单项都是CCNode的子类,可是Menu是CCLayer的子类。根据cocos2d最佳实践,你不该该建立很是大的层次结构,你应该让层次结构尽量的小。

  所以,这意味着,你可能须要把尽量多的菜单项放到一个菜单里面。由于,CCLayer是从CCNode派生出来的,它也能够run action。就是说,你能够对menu run action。

总结

  这里有这个教程的完整的所有源代码。但愿这个教程对你有帮助,若是你在使用cocos2d的button的时候有什么好的意见或好点子,请跟我分享!