
3.2 实现菜单
游戏中最常用的交互方式就是使用菜单按钮了,本节来实现Cocos2d-JS的菜单。Cocos中的菜单分为两部分,一个是Menu,一个是Menu下的MenuItem,一个Menu是由一个或多个MenuItem组成的,MenuItem又有MenuItemFont、MenuItem Image、MenuItemAtlasFont、MenuItemLabel、MenuItemSprite、MenuItemToggle等具体的菜单实现方式。
Menu与MenuItem以及MenuItem的各种实现子类的关系如图3-2所示。

图3-2 Menu、MenuItem及其子类关系图
图3-2清楚地描述了菜单中各种类的继承关系,其中Menu相当于一个菜单图层,里面放着各种各样的MenuItem,当然,在Cocos2d-JS中所有类的根都是Node。由该图可以看出,菜单项可以分为三大类,即文字菜单(MenuItemLabel)、精灵菜单(MenuItemSprite)和开关菜单(MenuItemToggle)。
以下通过具体的代码实现,从如何创建一个菜单开始来了解Cocos2d-JS的代码编写,本节的所有代码都在MenuDemo项目中。
3.2.1 实现文字菜单
文字菜单就是MenuItemLabel、MenuItemFont和MenuItemAtlasFont这3种,其中文字菜单的父类是MenuItemLabel,查看源码,可以看到它的构造方法如下。

可以看出,它需要的构造方法的参数有label、selector和target,分别代表Label控件、回调方法和添加的节点。以下代码是创建一个MenuItemLabel菜单项,使用LabelTTF标签,文字内容为MenuItemLabel,字体为Aria、字号为50,回调函数在控制台打印输出“LabelTTF, Aria,50”。

同样,MenuItemLabel的子类MenuItemFont的构造方法如下。

由源码的构造方法可以看出,它的参数只有value、callback和target,分别代表文字、回调函数和添加的节点。从代码实现可以看出,它实际上也是实例化了Menu ItemLabel,只不过提供了Label的默认实现,简化了文字菜单的生成步骤。以下代码是生成一个MenuItemFont菜单项,文本内容为MenuItemFont,回调函数打印日志输出“MenuItemFont”。

MenuItemLabel的另一个子类MenuItemAtlasFont相对复杂一点,它的构造方法如下。

MenuItemAtlasFont是基于图片集的文本菜单项,它的参数value、charMapFile、itemWidth、itemHeight、startCharMap、callback和target分别代表显示文本、图片集合文件、要截取的文字的图片宽度、要截取的文字的图片高度、图片起始字符、回调函数和添加的节点。
MenuItemAtlasFont是以自定义的文字图集来显示,可以用于显示游戏中的特定字体,以下代码创建了一个自定义字体的MenuItemAtlasFont菜单项。

以上是对所有文字菜单的介绍,在创建好了菜单项之后还需要创建Menu对象,再将这些MenuItem都放在Menu上,最后将Menu放到Layer图层上,代码如下。

写完以上代码后再运行项目,可以看到如图3-3所示的效果。

图3-3 文字菜单运行效果
3.2.2 实现精灵菜单
与文字菜单相比,精灵菜单能显示更加丰富的元素,精灵菜单的父类是MenuItemSprite,从源码看,它的构造方法如下。


如代码所示,MenuItemSprite的构造方法需要传5个参数,分别是normalSprite、selectedSprite、three、four、five,它们代表的含义分别是正常状态的Sprite、选中状态的Sprite、禁用状态的Sprite或添加节点、回调函数名字字符串或回调函数实现或添加节点、回调函数名字字符串或回调函数。由构造函数看出可根据需要选择是否构造参数来创建MenuItemSprite对象。
游戏中一些需要不同状态的精灵显示就需要用MenuItemSprite来实现,如下面的代码是创建了一个普通状态为图片是item1的精灵、选中状态为图片是item2的精灵、回调函数在控制台打印输出“MenuItemSprite”的MenuItemSprite菜单项。

在很多情况下不需要很复杂的精灵显示,只需要几张图片即可,而使用MenuItemSprite还需要创建几个精灵,再来创建菜单项,如果只想创建几张图片构成的菜单项,就可以使用MenuItemSprite的子类MenuItem Image,它的构造方法如下。

它的参数是normalImage、selected Image、three、four、five,分别代表正常状态图片、选中状态图片、禁用状态图片、回调函数和添加的节点。与MenuItemSprite相比,MenuItem Image省去了创建精灵的步骤,可以看到创建精灵的步骤都在构造函数中实现了,然后再调用MenuItemSprite,原理一样,但实现会更加容易。
例如,下面的代码创建了一个普通状态为图片是item1、选中状态为图片是item2、回调函数在控制台打印输出“MenuItem Image”的MenuItem Image菜单项。

将以上代码添加在上面的代码后面,再运行项目,可以看到如图3-4所示的效果。

图3-4 精灵菜单运行效果
3.2.3 实现开关菜单
开关菜单只有一个实现类,也就是MenuItemToggle,相比文字菜单项和精灵菜单项,开关菜单项相对来说用的比较少。开关菜单项是为了实现两个菜单项之间可以切换的效果。查看源码可以看到MenuItemToggle的构造方法如下。

从构造方法只能看到它把参数直接传递给了this.initWithItems,再具体往下看,看看这个调用的方法又做了什么事情。

从这个方法就可以看到从构造方法传进来的参数都做什么了,首先判断参数的个数,参数的前几个是MenuItem子项,然后根据参数中回调方法的位置来调用initWithCallback方法,构造MenuItem,可以再看看initWithCallback方法。

由以上几段代码可以总结出,创建MenuItemToggle可以带一个MenuItem数组,可以有一个或两个,还需要带一个回调方法。
MenuItemToggle非常适合在游戏中有状态切换的菜单项,如复选框是否选中状态等。例如下面的代码是创建文本“ON”的菜单项和文本“OFF”的菜单项和一个回调方法,单击输出切换状态。

继续将上面的代码添加到之前的代码后面,运行效果如图3-5所示。