cocos2dx基础篇(7)——菜单按钮CCMenu/CCMenuItem
【唠叨】
菜单按钮在游戏中是经常被用到的,比如主菜单界面的菜单选项,暂停游戏时的菜单选项等等。cocos2dx引擎同样为我们提供了CCMenu菜单的功能,并包含了一些简单的菜单项CCMenuItem。且菜单项附带触碰按钮时,自动放大的效果。
温馨提示:本节内容比较多,需要大家慢慢分析,不要急于求成。
本节组织结构如下:
一、介绍CCMenu。
二、介绍CCMenuItem,及其具体的六个子类。
三、代码实战。
【Demo下载】
https://github.com/shahdza/Cocos_LearningTest/tree/master/demo_%E8%8F%9C%E5%8D%95CCMenu%E3%80%81CCMenuItem
【3.x】
(1)去掉“CC”
(2)其他函数的增加与删除稍微做了变化,可以自己在开发过程中掌握。
【菜单CCMenu】
菜单CCMenu是专门用来承载菜单按钮的CCLayer图层,图层中的子节点只能够是菜单项CCMenuItem或其子类。通常先创建菜单项CCMenuItem,然后使用一个或多个菜单项生成菜单CCMenu,最后把CCMenu加入当前CCLayer图层。
继承关系如下:
如果直接在层中添加CCMenuItem也可以正常显示,但是无法响应回调函数,因为CCMenu是继承至CCLayer,也就继承了触摸的相关事件,而CCMenuItem只是从CCNode继承而来,并不响应触摸,因此无法调用回调函数。
由于CCMenu的父类为CCLayer,所以锚点为(0,0),且无法设置锚点。CCMenu的默认原点坐标为屏幕正中心(winSize.width/2, winSize.height/2)。
而对于CCMenuItem是添加在CCMenu层中的,所以CCMenuItem的位置是相对于CCMenu层的偏移位置。CCMenuItem相对于CCMenu的偏移量默认为(0,0),且菜单项的锚点默认为(0.5,0.5)。
如下图所示:
值得注意的是:CCMenu包含了多个子菜单项,每个子菜单项的位置都不一样,如果定义了CCMenu的位置,那它作为父节点会影响到所有的子菜单项的位置,所以一般我们都是吧CCMenu的位置设置在CCPointZero,然后设置CCMenuItem的位置(也就是相对父节点的偏移量)来定位整个菜单。
常用操作如下:
//classCC_DLLCCMenu:publicCCLayerRGBA{/***创建菜单的三个常用方法*///创建一个空菜单staticCCMenu*create();//CCMenu::create(item1,item2,item3,NULL);//用CCMenuItem菜单项创建菜单,最后以NULL表示结束.staticCCMenu*create(CCMenuItem*item,...);//用一个包含CCMenuItem的CCArray数组来创建菜单staticCCMenu*createWithArray(CCArray*pArrayOfItems);/***菜单布局方式*注意:使用以下函数进行菜单布局时,将会把整体菜单项的相对于CCMenu的偏移坐标设置到(0,0)。*所以布局后,应该设置CCMenu菜单的坐标为屏幕正中心(winSize.width/2,winSize.height/2),效果更加。*alignItemsVertically,alignItemsHorizontally,*alignItemsInColumns,alignItemsInRows*///让menu的所有item竖着布局//item1//item2//item3voidalignItemsVertically();//默认间隙:5个像素voidalignItemsVerticallyWithPadding(floatpadding);//相连两个item间隔为padding//让menu的所有item横着布局//item1item2item3voidalignItemsHorizontally();//默认间隙:5个像素voidalignItemsHorizontallyWithPadding(floatpadding);//相连两个item间隔为padding//将items进行分组,然后按列(columns)进行排列//每一组在同一行,参数columns表示每一组的菜单项个数,并以NULL表示结束。//alignItemsInColumns(3,2,1,NULL);//item1item2item3//item4item5//item6voidalignItemsInColumns(unsignedintcolumns,...);//将items进行分组,然后按行(rows)进行排列。与上述类似。//alignItemsInRows(3,2,1,NULL);//item1//item4//item2item6//item5//item3voidalignItemsInRows(unsignedintrows,...);/***添加、删除item菜单项*addChild,removeChild*/virtualvoidaddChild(CCNode*child);virtualvoidaddChild(CCNode*child,intzOrder);virtualvoidaddChild(CCNode*child,intzOrder,inttag);virtualvoidremoveChild(CCNode*child,boolcleanup);/***设置菜单是否可用*setEnabled*/virtualvoidsetEnabled(boolvalue){m_bEnabled=value;};virtualboolisEnabled(){returnm_bEnabled;}};//
【菜单项CCMenuItem】
CCMenuItem继承自CCNode,所以它的子类菜单项都可以使用CCNode的相关操作。
CCMenuItem是所有菜单项的父类,建议不要直接使用该类,因为它并不包含具体显示的功能。
作为其它菜单项的父类,主要提供了一下三个功能:
(1)提供了基本按钮的状态:正常、选中、禁用。
(2)为按钮实现了基本的回调函数机制。当玩家点积按钮后,就会调用执行相应的回调函数。
(3)触碰菜单项,附有自动放大效果。
菜单项的子类可以分成三类,总共六个:
(1)文字菜单项:CCMenuItemLabel、CCMenuItemAtlasFont、CCMenuItemFont;
(2)图片菜单项:CCMenuItemSprite、CCMenuItemImage;
(3)切换菜单项:CCMenuItemToggle。
继承关系如下图所示:
1、CCMenuItemLabel
CCMenuItemLabel是一个包含了文字标签的菜单项按钮,CCLabel的三个标签CCLabelBMFont ,CCLabelAtlas,CCLabelTTF对象,都可以放置在该按钮对象中。
常用操作如下:
//classCC_DLLCCMenuItemLabel:publicCCMenuItem{/***创建CCMenuItemLabel*支持字体标签类:CCLabelBMFont,CCLabelAtlas,CCLabelTTF*///用label字体标签创建,不设置回调响应事件。//label可以是CCLabelBMFont,CCLabelAtlas,CCLabelTTF三种文字标签。staticCCMenuItemLabel*create(CCNode*label);//用label字体标签创建,并设置回调响应事件。//target:执行当前按钮的对象,一般为this。表示由CCLayer图层执行回调响应事件。//selector:使用菜单回调函数menu_selector。一般在当前CCLayer图层中定义。//create(label,this,menu_selector(HelloWorld::func1));staticCCMenuItemLabel*create(CCNode*label,CCObject*target,SEL_MenuHandlerselector);/***属性设置*setString,setEnabled,setDisabledColor,setLabel*///设置内部字体标签(CCLabel)的显示文字内容voidsetString(constchar*label);//设置该CCMenuItemLabel对象是否可用virtualvoidsetEnabled(boolenabled);virtualboolisSelected();//禁用时的颜色virtualvoidsetDisabledColor(ccColor3B&);virtualconstccColor3B&getDisabledColor();//被渲染的字体,可以是CCLabelBMFont,CCLabelAtlas,CCLabelTTF。virtualvoidsetLabel(CCNode*);virtualCCNode*getLabel();};//
2、CCMenuItemAtlasFont
CCMenuItemAtlasFont的父类为CCMenuItemLabel。
和父类的区别在于:该类在创建时,只要设置显示内容、使用的字体资源.png即可。它默认使用CCLabelAtlas来创建文字标签的菜单项按钮。而省去了父类创建label的步骤。
该类和父类相比,并未做其他属性或函数的扩展。
常用操作如下:
//classCC_DLLCCMenuItemFont:publicCCMenuItemLabel{/***创建CCMenuItemFont*///创建基于CCLabelAtlas字体标签的CCMenuItemAtlasFont,不带回调响应事件。//create("20140818","digit.png",20,20,'0');//create("20140818","digit.png",20,20,'0',this,menu_selector(HelloWorld::func2));staticCCMenuItemAtlasFont*create(constchar*value,constchar*charMapFile,intitemWidth,intitemHeight,charstartCharMap);staticCCMenuItemAtlasFont*create(constchar*value,constchar*charMapFile,intitemWidth,intitemHeight,charstartCharMap,CCObject*target,SEL_MenuHandlerselector);};//
3、CCMenuItemFont
CCMenuItemAtlasFont的父类为CCMenuItemLabel。
和父类的区别在于:该类在创建时,只要设置显示内容即可。它默认使用CCLabelTTF来创建文字标签的菜单项按钮。而省去了父类创建label的步骤。
和父类相比,可以设置字体大小。
常用操作如下:
//classCC_DLLCCMenuItemFont:publicCCMenuItemLabel{/***创建CCMenuItemFont*///create(要显示的字符串)//create(要显示的字符串,执行当前按钮的对象,回调函数)//target:执行当前按钮的对象,一般为this。表示由CCLayer图层执行回调响应事件。//selector:使用菜单回调函数menu_selector。一般在当前CCLayer图层中定义。//create("hello",this,menu_selector(HelloWorld::func3));staticCCMenuItemFont*create(constchar*value);staticCCMenuItemFont*create(constchar*value,CCObject*target,SEL_MenuHandlerselector);/***属性设置*///这是一个全局静态方法,用来设置新创建CCMenuItemFont时的默认字体大小的//在不进行设置时,创建的CCMenuItemFont,默认大小为32。//CCMenuItemFont::setFontSize(32);staticvoidsetFontSize(unsignedints);staticunsignedintfontSize();//这是一个全局静态方法,用来设置新创建CCMenuItemFont时的默认字体资源.fnt的//在不进行设置时,创建的CCMenuItemFont,默认字体为"MarkerFelt"。//CCMenuItemFont::setFontName("Arial");staticvoidsetFontName(constchar*name);staticconstchar*fontName();//设置该对象的字体大小及使用的字体资源名.fntvoidsetFontSizeObj(unsignedints);unsignedintfontSizeObj();voidsetFontNameObj(constchar*name);constchar*fontNameObj();};//
4、CCMenuItemSprite
CCMenuItemSprite是一个由精灵对象组成的菜单按钮。
此类的内部属性提供了三个精灵对象,分别表示按钮的三个状态:正常、选中、禁用。每种状态都分别对应了一个精灵图片。
精灵是引擎中最为丰富和自由的元素,因此类CCMenuItemSprite算得上是将精灵和按钮功能的结合体。
常用操作如下:
//classCC_DLLCCMenuItemSprite:publicCCMenuItem{/***创建CCMenuItemSprite*///参数://normalSprite:正常时的默认精灵normalSprite//selectedSprite:被选中时的精灵selectedSprite//disabledSprite:禁用时的精灵disabledSprite//target:执行当前按钮的对象,一般为this。表示由CCLayer图层执行回调响应事件。//selector:使用菜单回调函数menu_selector。一般在当前CCLayer图层中定义。//CCSprite*normalSprite=CCSprite::create("sp1.png");//CCSprite*selectedSprite=CCSprite::create("sp2.png");//CCSprite*disabledSprite=CCSprite::create("sp3.png");//create(normalSprite,selectedSprite,disabledSprite,this,menu_selector(HelloWorld::func4));staticCCMenuItemSprite*create(CCNode*normalSprite,CCNode*selectedSprite,CCNode*disabledSprite=NULL);staticCCMenuItemSprite*create(CCNode*normalSprite,CCNode*selectedSprite,CCObject*target,SEL_MenuHandlerselector);staticCCMenuItemSprite*create(CCNode*normalSprite,CCNode*selectedSprite,CCNode*disabledSprite,CCObject*target,SEL_MenuHandlerselector);/***设置三种状态的精灵CCSprite*///正常时的默认图片normalSprite//被选中时的图片selectedSprite//禁用时的图片disabledSpritevirtualvoidsetNormalImage(CCNode*normalSprite);virtualCCNode*getNormalImage();virtualvoidsetSelectedImage(CCNode*selectedSprite);virtualCCNode*getSelectedImage();virtualvoidsetDisabledImage(CCNode*disabledSprite);virtualCCNode*getDisabledImage();/***设置选中、禁用*/virtualvoidselected();//选中virtualvoidunselected();//取消选中virtualvoidsetEnabled(boolbEnabled);//是否启用。false禁用。};//
5、CCMenuItemImage
CCMenuItemImage继承自CCMenuItemSprite,并没有太大的变化。只是提供了更为简捷的方式,将原本按钮中的精灵对象换为了三张纹理图片。无需创建精灵对象,就可以直接创建一个精灵按钮对象。
与父类相比,省去了创建CCSprite精灵对象的过程。实际上在create创建的过程中,已经帮你做了创建CCSprite的过程了。
常用操作如下:
//classCC_DLLCCMenuItemImage:publicCCMenuItemSprite{/***创建CCMenuItemImage*///与CCMenuItemSprite创建方式差不多。就是参数变成了图片资源(如*.png)//create("sp1.png","sp2.png","sp3.png",this,menu_selector(HelloWorld::func5));staticCCMenuItemImage*create(constchar*normalImage,constchar*selectedImage);staticCCMenuItemImage*create(constchar*normalImage,constchar*selectedImage,constchar*disabledImage);staticCCMenuItemImage*create(constchar*normalImage,constchar*selectedImage,CCObject*target,SEL_MenuHandlerselector);staticCCMenuItemImage*create(constchar*normalImage,constchar*selectedImage,constchar*disabledImage,CCObject*target,SEL_MenuHandlerselector);/***属性设置*///用CCSpriteFrame精灵帧,设置正常时的精灵帧NormalvoidsetNormalSpriteFrame(CCSpriteFrame*frame);//用CCSpriteFrame精灵帧,设置选中时的精灵帧SelectedvoidsetSelectedSpriteFrame(CCSpriteFrame*frame);//用CCSpriteFrame精灵帧,设置禁用时的精灵帧DisabledvoidsetDisabledSpriteFrame(CCSpriteFrame*frame);};//
6、CCMenuItemToggle
CCMenuItemToggle是比较特殊的。它在内部拥有一个CCMenuItem菜单项数组,用来负责展示不同的菜单项按钮状态。因为使用了一个菜单按钮的数组,所以此类的对象可以实现状态的切换。此类是一个菜单项按钮对象的集合,能够包含很多的菜单项按钮状态,方便开发者进行切换。
例如,CCMenuItemToggle可以用来做开关按钮。
常用操作如下:
//classCC_DLLCCMenuItemToggle:publicCCMenuItem{/***创建CCMenuItemToggle*create或createWithTarget*///使用一个菜单项创建CCMenuItemToggle对象//CCMenuItemFont*item=CCMenuItemFont::create("hello");//CCMenuItemToggle::create(item);staticCCMenuItemToggle*create(CCMenuItem*item);//使用菜单项参数列表创建,以NULL结束列表//item1=CCMenuItemFont::create("hello");//item2=CCSprite::create("sp1.png")://createWithTarget(this,menu_selector(HelloWorld::func6),item1,item2,NULL);staticCCMenuItemToggle*createWithTarget(CCObject*target,SEL_MenuHandlerselector,CCMenuItem*item,...);//使用包含菜单项的数组创建//createWithTarget(this,menu_selector(HelloWorld::func6),pArray);staticCCMenuItemToggle*createWithTarget(CCObject*target,SEL_MenuHandlerselector,CCArray*menuItems);/***菜单项数组集合相关*setSelectedIndex,selectedItem,*setSubItems,addSubItem*///设置当前选中的CCMenuItem的索引值(即数组下标)virtualvoidsetSelectedIndex(unsignedint);virtualunsignedintgetSelectedIndex();//返回当前选中的菜单项CCMenuItem*selectedItem();//设置CCMenuItem菜单项数组集合virtualvoidsetSubItems(CCArray*);virtualCCArray*getSubItems();//添加新的子菜单项voidaddSubItem(CCMenuItem*item);};//
【代码实战】
首先,在实战的过程中会遇到有关回调函数的概念,这里就简单来说一下什么事回调函数。
回调函数其实就是:当按钮被触碰时,会执行相应的函数。类似于鼠标点击绑定的click响应事件处理函数。
1、在HelloWorldScene.h中添加如下两个回调函数
////添加回调响应函数voidmenuItemFont2Func(CCObject*sender);//更改标签内容voidmenuItemToggleFunc(CCObject*sender);//更改状态:正常,选中,禁用//
2、编写测试代码
//boolHelloWorld::init(){if(!CCLayer::init()){returnfalse;}//获取可视区域尺寸大小CCSizemysize=CCDirector::sharedDirector()->getVisibleSize();//获取可视区域的原点位置CCPointorigin=CCDirector::sharedDirector()->getVisibleOrigin();//屏幕正中心位置CCPointmidPos=ccp(mysize.width/2,mysize.height/2);/**创建CCMenuItemLabel*使用CCLabelTTF创建*/CCLabelTTF*lb1=CCLabelTTF::create("aaaaaa","Arial",32);CCMenuItemLabel*menuItemLabel=CCMenuItemLabel::create(lb1);//设置位置menuItemLabel->setPosition(ccp(120,mysize.height-50));/**创建CCMenuItemAtlasFont*创建方式与CCLabelAtlas类似*/CCMenuItemAtlasFont*menuItemAtlas=CCMenuItemAtlasFont::create("20140818","fonts/digit.png",20,20,'0');menuItemAtlas->setPosition(ccp(120,mysize.height-120));/**创建CCMenuItemFont*创建了两个,有无附带回调响应函数*///设置CCMenuItemFont创建时的默认字体大小CCMenuItemFont::setFontSize(50);//不带回调响应函数,tag编号为1CCMenuItemFont*menuItemFont1=CCMenuItemFont::create("11111");menuItemFont1->setTag(1);//触碰后,执行回调函数menuItemFont2Func。更改menuItemFont1的内容CCMenuItemFont*menuItemFont2=CCMenuItemFont::create("Change1",this,menu_selector(HelloWorld::menuItemFont2Func));//回调menuItemFont2->setFontSizeObj(32);//设置字体大小menuItemFont1->setPosition(ccp(120,mysize.height-190));//设置位置menuItemFont2->setPosition(ccp(120,mysize.height-260));//设置位置/**创建CCMenu,tag编号为100*菜单项menuItemLabel,menuItemAtlas,menuItemFont1,menuItemFont2*/CCMenu*menu=CCMenu::create(menuItemLabel,menuItemAtlas,menuItemFont1,menuItemFont2,NULL);//设置位置为(0,0),与HelloWorld层重合menu->setPosition(CCPointZero);//将CCMenu菜单添加到CCLayer中,tag编号为100this->addChild(menu,0,100);/**创建CCMenuItemSprite*参数为CCSprite精灵*/CCSprite*sp1=CCSprite::create("sp1.png");CCSprite*sp2=CCSprite::create("sp2.png");CCSprite*sp3=CCSprite::create("sp3.png");CCMenuItemSprite*menuItemSprite=CCMenuItemSprite::create(sp1,sp2,sp3);menuItemSprite->setPosition(ccp(mysize.width/2+50,mysize.height/2+50));menu->addChild(menuItemSprite);//添加到菜单层中menuItemSprite->setTag(2);//tag编号为2/**创建CCMenuItemImage*参数变成纹理图片png*///使用CCMenuItemImage创建一个关闭程序的菜单项按钮CCMenuItemImage*menuItemImage=CCMenuItemImage::create("CloseNormal.png","CloseSelected.png",this,menu_selector(HelloWorld::menuCloseCallback));//回调menuItemImage->setPosition(ccp(mysize.width-40,mysize.height-40));menu->addChild(menuItemImage);//添加到菜单层中/**创建CCMenuItemToggle*参数为CCMenuItem子类*/CCMenuItemFont::setFontSize(20);CCMenuItemFont*menuItemFont3=CCMenuItemFont::create("Toggle_Normal");CCMenuItemFont*menuItemFont4=CCMenuItemFont::create("Toggle_Selected");CCMenuItemImage*menuItemImage2=CCMenuItemImage::create("sp3.png","sp1.png");//创建CCMenuItemToggle,回调函数:更改menuItemSprite的状态。CCMenuItemToggle*menuItemToggle=CCMenuItemToggle::createWithTarget(this,menu_selector(HelloWorld::menuItemToggleFunc),menuItemFont3,menuItemFont4,NULL);//菜单项参数列表menuItemToggle->setPosition(ccp(mysize.width/2+50,mysize.height/2-50));//设置位置//将menuItemImage2添加到menuItemToggle中menuItemToggle->addSubItem(menuItemImage2);menu->addChild(menuItemToggle);//添加到菜单层中returntrue;}//
3、编写回调响应函数的代码
///**回调函数menuItemFont2Func*///变化menuItemFont1的内容voidHelloWorld::menuItemFont2Func(CCObject*sender){//获取menuItemFont2CCMenuItemFont*menuItemFont2=(CCMenuItemFont*)sender;//从CCLayer中获取CCMenu菜单CCMenu*menu=(CCMenu*)this->getChildByTag(100);//获取menuItemFont1,其tag为1//!!!注意!!!//tag是相对父节点而言的:this的子节点中没有tag为1,而menuItemFont1是menu中tag为1的子节点。CCMenuItemFont*menuItemFont1=(CCMenuItemFont*)menu->getChildByTag(1);//更改menuItemFont1的内容//获取menuItemFont2显示的标签内容CCLabelTTF*lb=(CCLabelTTF*)menuItemFont2->getLabel();//strcmp判断是否等于Change1if(strcmp(lb->getString(),"Change1")==0){lb->setString("Change2");menuItemFont1->setString("22222");}else{lb->setString("Change1");menuItemFont1->setString("11111");}}/**回调函数menuItemToggleFunc*///更改状态:正常,选中,禁用voidHelloWorld::menuItemToggleFunc(CCObject*sender){//获取menuItemToggleCCMenuItemToggle*menuItemToggle=(CCMenuItemToggle*)sender;//从CCLayer中获取CCMenu菜单CCMenu*menu=(CCMenu*)this->getChildByTag(100);//获取menuItemSpriteCCMenuItemSprite*menuItemSprite=(CCMenuItemSprite*)menu->getChildByTag(2);//根据menuItemToggle当前被选中的是哪一项,来设置menuItemSprite的状态switch(menuItemToggle->getSelectedIndex()){case0://正常menuItemSprite->setEnabled(true);break;case1://选中menuItemSprite->selected();break;case2://禁用menuItemSprite->setEnabled(false);break;}}//
4、运行结果截图
点击Change1按钮,执行回调函数menuItemFont2Func。“11111”变成“22222”。
点击“Toggle_Normal”按钮,精灵图片变成选中时的图片。
再次点击“Toggle_Selected”按钮,精灵图片变成禁用时的图片。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。