您好,登錄后才能下訂單哦!
【嘮叨】
菜單按鈕在游戲中是經常被用到的,比如主菜單界面的菜單選項,暫停游戲時的菜單選項等等。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的位置(也就是相對父節點的偏移量)來定位整個菜單。
常用操作如下:
// class CC_DLL CCMenu : public CCLayerRGBA { /** * 創建菜單的三個常用方法 */ //創建一個空菜單 static CCMenu* create(); //CCMenu::create(item1,item2,item3,NULL); //用CCMenuItem菜單項創建菜單,最后以NULL表示結束. static CCMenu* create(CCMenuItem* item, ...); //用一個包含CCMenuItem的CCArray數組來創建菜單 static CCMenu* createWithArray(CCArray* pArrayOfItems); /** * 菜單布局方式 * 注意:使用以下函數進行菜單布局時,將會把整體菜單項的相對于CCMenu的偏移坐標設置到(0,0)。 * 所以布局后,應該設置CCMenu菜單的坐標為屏幕正中心(winSize.width/2, winSize.height/2),效果更加。 * alignItemsVertically , alignItemsHorizontally , * alignItemsInColumns , alignItemsInRows */ //讓menu的所有item豎著布局 //item1 //item2 //item3 void alignItemsVertically(); //默認間隙:5個像素 void alignItemsVerticallyWithPadding(float padding); //相連兩個item間隔為padding //讓menu的所有item橫著布局 //item1 item2 item3 void alignItemsHorizontally(); //默認間隙:5個像素 void alignItemsHorizontallyWithPadding(float padding); //相連兩個item間隔為padding //將items進行分組,然后按列(columns)進行排列 //每一組在同一行,參數columns表示每一組的菜單項個數,并以NULL表示結束。 //alignItemsInColumns(3,2,1,NULL); //item1 item2 item3 // item4 item5 // item6 void alignItemsInColumns(unsigned int columns, ...); //將items進行分組,然后按行(rows)進行排列。與上述類似。 //alignItemsInRows(3,2,1,NULL); //item1 // item4 //item2 item6 // item5 //item3 void alignItemsInRows(unsigned int rows, ...); /** * 添加、刪除item菜單項 * addChild , removeChild */ virtual void addChild(CCNode * child); virtual void addChild(CCNode * child, int zOrder); virtual void addChild(CCNode * child, int zOrder, int tag); virtual void removeChild(CCNode* child, bool cleanup); /** * 設置菜單是否可用 * setEnabled */ virtual void setEnabled(bool value) { m_bEnabled = value; }; virtual bool isEnabled() { return m_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對象,都可以放置在該按鈕對象中。
常用操作如下:
// class CC_DLL CCMenuItemLabel : public CCMenuItem { /** * 創建CCMenuItemLabel * 支持字體標簽類:CCLabelBMFont , CCLabelAtlas , CCLabelTTF */ //用label字體標簽創建,不設置回調響應事件。 //label可以是CCLabelBMFont , CCLabelAtlas , CCLabelTTF三種文字標簽。 static CCMenuItemLabel* create(CCNode *label); //用label字體標簽創建,并設置回調響應事件。 // target:執行當前按鈕的對象,一般為this。表示由CCLayer圖層執行回調響應事件。 // selector:使用菜單回調函數menu_selector。一般在當前CCLayer圖層中定義。 //create( label, this , menu_selector( HelloWorld::func1 ) ); static CCMenuItemLabel * create(CCNode*label, CCObject* target, SEL_MenuHandler selector); /** * 屬性設置 * setString , setEnabled , setDisabledColor , setLabel */ //設置內部字體標簽(CCLabel)的顯示文字內容 void setString(const char * label); //設置該CCMenuItemLabel對象是否可用 virtual void setEnabled(bool enabled); virtual bool isSelected(); //禁用時的顏色 virtual void setDisabledColor(ccColor3B&); virtual const ccColor3B& getDisabledColor(); //被渲染的字體,可以是CCLabelBMFont , CCLabelAtlas , CCLabelTTF。 virtual void setLabel(CCNode*); virtual CCNode* getLabel(); }; //
2、CCMenuItemAtlasFont
CCMenuItemAtlasFont的父類為CCMenuItemLabel。
和父類的區別在于:該類在創建時,只要設置顯示內容、使用的字體資源.png即可。它默認使用CCLabelAtlas來創建文字標簽的菜單項按鈕。而省去了父類創建label的步驟。
該類和父類相比,并未做其他屬性或函數的擴展。
常用操作如下:
// class CC_DLL CCMenuItemFont : public CCMenuItemLabel { /** * 創建CCMenuItemFont */ //創建基于CCLabelAtlas字體標簽的CCMenuItemAtlasFont,不帶回調響應事件。 //create("20140818" , "digit.png" , 20 , 20 , '0' ); //create("20140818" , "digit.png" , 20 , 20 , '0' , this , menu_selector( HelloWorld::func2 ) ); static CCMenuItemAtlasFont* create(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap); static CCMenuItemAtlasFont* create(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap, CCObject* target, SEL_MenuHandler selector); }; //
3、CCMenuItemFont
CCMenuItemAtlasFont的父類為CCMenuItemLabel。
和父類的區別在于:該類在創建時,只要設置顯示內容即可。它默認使用CCLabelTTF來創建文字標簽的菜單項按鈕。而省去了父類創建label的步驟。
和父類相比,可以設置字體大小。
常用操作如下:
// class CC_DLL CCMenuItemFont : public CCMenuItemLabel { /** * 創建CCMenuItemFont */ //create(要顯示的字符串) //create(要顯示的字符串,執行當前按鈕的對象,回調函數) // target:執行當前按鈕的對象,一般為this。表示由CCLayer圖層執行回調響應事件。 // selector:使用菜單回調函數menu_selector。一般在當前CCLayer圖層中定義。 //create( "hello" , this , menu_selector( HelloWorld::func3 ) ); static CCMenuItemFont * create(const char *value); static CCMenuItemFont * create(const char *value, CCObject* target, SEL_MenuHandler selector); /** * 屬性設置 */ //這是一個全局靜態方法,用來設置新創建CCMenuItemFont時的默認字體大小的 //在不進行設置時,創建的CCMenuItemFont,默認大小為32。 //CCMenuItemFont::setFontSize(32); static void setFontSize(unsigned int s); static unsigned int fontSize(); //這是一個全局靜態方法,用來設置新創建CCMenuItemFont時的默認字體資源.fnt的 //在不進行設置時,創建的CCMenuItemFont,默認字體為"Marker Felt"。 //CCMenuItemFont::setFontName("Arial"); static void setFontName(const char *name); static const char *fontName(); //設置該對象的字體大小及使用的字體資源名.fnt void setFontSizeObj(unsigned int s); unsigned int fontSizeObj(); void setFontNameObj(const char* name); const char* fontNameObj(); }; //
4、CCMenuItemSprite
CCMenuItemSprite是一個由精靈對象組成的菜單按鈕。
此類的內部屬性提供了三個精靈對象,分別表示按鈕的三個狀態:正常、選中、禁用。每種狀態都分別對應了一個精靈圖片。
精靈是引擎中最為豐富和自由的元素,因此類CCMenuItemSprite算得上是將精靈和按鈕功能的結合體。
常用操作如下:
// class CC_DLL CCMenuItemSprite : public CCMenuItem { /** * 創建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) ); static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite = NULL); static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCObject* target, SEL_MenuHandler selector); static CCMenuItemSprite * create(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite, CCObject* target, SEL_MenuHandler selector); /** * 設置三種狀態的精靈CCSprite */ //正常時的默認圖片normalSprite //被選中時的圖片selectedSprite //禁用時的圖片disabledSprite virtual void setNormalImage(CCNode* normalSprite); virtual CCNode* getNormalImage(); virtual void setSelectedImage(CCNode* selectedSprite); virtual CCNode* getSelectedImage(); virtual void setDisabledImage(CCNode* disabledSprite); virtual CCNode* getDisabledImage(); /** * 設置選中、禁用 */ virtual void selected(); //選中 virtual void unselected(); //取消選中 virtual void setEnabled(bool bEnabled); //是否啟用。false禁用。 }; //
5、CCMenuItemImage
CCMenuItemImage繼承自CCMenuItemSprite,并沒有太大的變化。只是提供了更為簡捷的方式,將原本按鈕中的精靈對象換為了三張紋理圖片。無需創建精靈對象,就可以直接創建一個精靈按鈕對象。
與父類相比,省去了創建CCSprite精靈對象的過程。實際上在create創建的過程中,已經幫你做了創建CCSprite的過程了。
常用操作如下:
// class CC_DLL CCMenuItemImage : public CCMenuItemSprite { /** * 創建CCMenuItemImage */ //與CCMenuItemSprite創建方式差不多。就是參數變成了圖片資源(如*.png) //create("sp1.png", "sp2.png", "sp3.png", this, menu_selector(HelloWorld::func5) ); static CCMenuItemImage* create(const char *normalImage, const char *selectedImage); static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, const char *disabledImage); static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, CCObject* target, SEL_MenuHandler selector); static CCMenuItemImage* create(const char *normalImage, const char *selectedImage, const char *disabledImage, CCObject* target, SEL_MenuHandler selector); /** * 屬性設置 */ //用CCSpriteFrame精靈幀,設置正常時的精靈幀Normal void setNormalSpriteFrame(CCSpriteFrame* frame); //用CCSpriteFrame精靈幀,設置選中時的精靈幀Selected void setSelectedSpriteFrame(CCSpriteFrame* frame); //用CCSpriteFrame精靈幀,設置禁用時的精靈幀Disabled void setDisabledSpriteFrame(CCSpriteFrame* frame); }; //
6、CCMenuItemToggle
CCMenuItemToggle是比較特殊的。它在內部擁有一個CCMenuItem菜單項數組,用來負責展示不同的菜單項按鈕狀態。因為使用了一個菜單按鈕的數組,所以此類的對象可以實現狀態的切換。此類是一個菜單項按鈕對象的集合,能夠包含很多的菜單項按鈕狀態,方便開發者進行切換。
例如,CCMenuItemToggle可以用來做開關按鈕。
常用操作如下:
// class CC_DLL CCMenuItemToggle : public CCMenuItem { /** * 創建CCMenuItemToggle * create 或 createWithTarget */ //使用一個菜單項創建CCMenuItemToggle對象 //CCMenuItemFont* item = CCMenuItemFont::create("hello"); //CCMenuItemToggle::create(item); static CCMenuItemToggle* create(CCMenuItem *item); //使用菜單項參數列表創建,以NULL結束列表 //item1 = CCMenuItemFont::create("hello"); //item2 = CCSprite::create("sp1.png"): //createWithTarget(this, menu_selector(HelloWorld::func6), item1, item2, NULL); static CCMenuItemToggle* createWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, ...); //使用包含菜單項的數組創建 //createWithTarget(this, menu_selector(HelloWorld::func6), pArray); static CCMenuItemToggle * createWithTarget(CCObject* target, SEL_MenuHandler selector, CCArray* menuItems); /** * 菜單項數組集合相關 * setSelectedIndex , selectedItem , * setSubItems , addSubItem */ //設置當前選中的CCMenuItem的索引值(即數組下標) virtual void setSelectedIndex(unsigned int ); virtual unsigned int getSelectedIndex(); //返回當前選中的菜單項 CCMenuItem* selectedItem(); //設置CCMenuItem菜單項數組集合 virtual void setSubItems(CCArray* ); virtual CCArray* getSubItems(); //添加新的子菜單項 void addSubItem(CCMenuItem *item); }; //
【代碼實戰】
首先,在實戰的過程中會遇到有關回調函數的概念,這里就簡單來說一下什么事回調函數。
回調函數其實就是:當按鈕被觸碰時,會執行相應的函數。類似于鼠標點擊綁定的click響應事件處理函數。
1、在HelloWorldScene.h中添加如下兩個回調函數
// //添加回調響應函數 void menuItemFont2Func(CCObject* sender); //更改標簽內容 void menuItemToggleFunc(CCObject* sender); //更改狀態:正常,選中,禁用 //
2、編寫測試代碼
// bool HelloWorld::init() { if ( !CCLayer::init() ) { return false; } //獲取可視區域尺寸大小 CCSize mysize = CCDirector::sharedDirector()->getVisibleSize(); //獲取可視區域的原點位置 CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); //屏幕正中心位置 CCPoint midPos = 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編號為1 CCMenuItemFont* 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編號為100 this->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); //添加到菜單層中 return true; } //
3、編寫回調響應函數的代碼
// /* * 回調函數menuItemFont2Func */ //變化menuItemFont1的內容 void HelloWorld::menuItemFont2Func(CCObject* sender) { //獲取menuItemFont2 CCMenuItemFont* 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判斷是否等于Change1 if( strcmp( lb->getString() , "Change1") == 0 ) { lb->setString("Change2"); menuItemFont1->setString("22222"); }else { lb->setString("Change1"); menuItemFont1->setString("11111"); } } /* * 回調函數menuItemToggleFunc */ //更改狀態:正常,選中,禁用 void HelloWorld::menuItemToggleFunc(CCObject* sender) { //獲取menuItemToggle CCMenuItemToggle* menuItemToggle = (CCMenuItemToggle*)sender; //從CCLayer中獲取CCMenu菜單 CCMenu* menu = (CCMenu*)this->getChildByTag(100); //獲取menuItemSprite CCMenuItemSprite* menuItemSprite = (CCMenuItemSprite*)menu->getChildByTag(2); //根據menuItemToggle當前被選中的是哪一項,來設置menuItemSprite的狀態 switch( menuItemToggle->getSelectedIndex() ) { case 0: //正常 menuItemSprite->setEnabled(true); break; case 1: //選中 menuItemSprite->selected(); break; case 2: //禁用 menuItemSprite->setEnabled(false); break; } } //
4、運行結果截圖
點擊Change1按鈕,執行回調函數menuItemFont2Func。“11111”變成“22222”。
點擊“Toggle_Normal”按鈕,精靈圖片變成選中時的圖片。
再次點擊“Toggle_Selected”按鈕,精靈圖片變成禁用時的圖片。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。