cocos2dx 3.1從零學習(二)——菜單、場景切換、場景傳值
回想一下上一篇的內容,我們已經學會了創建一個新的場景scene,加入sprite和label到層中。掌握了定時事件schedule。
我們能夠順利的寫出打飛機的主場景框架。
上一篇的內容我練習了七個新場景。每個場景都展示不同的東西。像背景定時切換、各種字體的隨機顏色和位置等。每次要切換一個場景都要改動AppDelegate中的調用代碼。很的不方便查看,這一篇我們寫場景的切換。每當我們創建一個新的場景的時候僅僅要加入相應button到主界面,點擊即能夠切換過去查看相應的效果。這個有點類似官方提供的cpptest的查看方式,所以說場景切換是很easy易用的功能。
要點擊切換場景,必需要有button能夠接收消息
Menu創建菜單
MenuItem Create 菜單子項的創建
MenuItemFont是字菜子項。
auto item= MenuItemFont::create("Hello,Menu",CC_CALLBACK_1(MenuScene::Menutest, this));
"Hello, Menu"是菜單子項button的文字。
MenuScene::Menutest是回調函數,它的參數是Menutest(Ref * pSender),這個參數類型是什麽能夠通過查看create定義來獲得。
CC_CALLBACK_1就是綁定一個函數為回調函數,
我們的第一個菜單能夠這樣寫:
//開頭這四句肯定是加入到init()函數裏的 auto item= MenuItemFont::create("Hello,Menu",CC_CALLBACK_1(MenuScene::Menutest, this)); auto menu= Menu::create(); menu->addchild(item); this->addchild(menu); voidMenuScene::Menutest(Ref *ref){ //此處能夠加入一個精靈,每點擊一次菜單button就加入一個精靈到場景中。}
還能夠這樣創建一個菜單
auto item =MenuItemFont::create("Hello, Menu",CC_CALLBACK_1(MenuScene::Menutest,this)); auto item1 =MenuItemFont::create("Ruck, Menu",CC_CALLBACK_1(MenuScene::Menutest1, this)); auto item2 =MenuItemFont::create("Click, Menu",CC_CALLBACK_1(MenuScene::Menutest2, this)); auto item3 =MenuItemFont::create("KTWork", CC_CALLBACK_1(MenuScene::KTWork,this)); auto item4 =MenuItemFont::create("PushScene", CC_CALLBACK_1(MenuScene::PushScene,this)); auto item5 =MenuItemFont::create("HomeWork", CC_CALLBACK_1(MenuScene::HomeWork,this)); auto item6 =MenuItemFont::create("HomeWork0617",CC_CALLBACK_1(MenuScene::HomeWorkSnow, this)); auto item7 =MenuItemFont::create("KT0618", CC_CALLBACK_1(MenuScene::KT0618,this)); auto menu =Menu::create(item, item1, item2, item3, item4, item5 ,item6,item7,<span style="color:#ff0000;">NULL);//註意最後一個參數為空</span> menu->setPosition(Director::getInstance()->getVisibleSize().width/ 2,Director::getInstance()->getVisibleSize().height / 2); menu->alignItemsVerticallyWithPadding(40);//看英文就知道是垂直對齊 間隔40像素 this->addchild(menu);
在回調函數中操作菜單子項的屬性:
voidMenuScene::Menutest1(Ref *ref){
MenuItemFont *item =(MenuItemFont *)ref;//全部的類的基類Ref,我們在菜單中是通過MenuItemFont創建的item。所以在回調函數中能夠強制轉換回MenuItemFont類型。然後就能夠在回調函數中改動菜單子項的屬性了。
if (item->getColor() == Color3B::RED) { item->setColor(Color3B::GREEN); item->setFontSizeObj(55); item->setFontNameObj("Baskerville-Boldltalic"); item->setString("GreenClick"); } else { item->setColor(Color3B::RED); item->setFontSizeObj(24); item->setFontName("Baskerville-Boldltalic"); item->setString("RedClick"); } }
從上面代碼能夠看到我創建了一個菜單裏面有非常多子項,這些子項都是場景切換。
每個新的場景都是一個練習。
見效果圖:
關於創建菜單子項還有非常多方法:
MenuItemLabel、MenuItemImage、MenuItemSprite等
以下拿MenuItemLabel舉例(futura-48.fnt在我第一篇打飛機源代碼的素材裏,源代碼在一樓,這樣的字體除了fnt另一個png文件,是一起的。不能分開。這樣的字體創建的菜單就是下圖中黃色的效果。)
autoitem2 =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt","Start"), CC_CALLBACK_1(MenuSceneTwo::MenuTest, this));
詳細的效果圖看以下:
這是我的第一個Hello,Menu場景
上面已經介紹了菜單的創建,嘗試這去創建一個新場景吧,點擊button能夠切換不同的背景。
給菜單子項綁定數據
在這裏還要學習菜單子項item的兩個操作函數。setUserData和setUserObject。
setUserData看定義接收的是void*參數,能夠接收隨意類型的數據。我們能夠用它來傳遞C++的基本類型數據,可是千萬不要自己new一些變量來傳值,會造成意外的。
setUserObject接收的是繼承自Ref的子類。繼承自Ref的子類,最經常使用的就是cocos2dx本身的String了。
auto item1 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Easy"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item1->setUserObject(String::create("Easy")); auto item2 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Hard"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item2->setUserObject(String::create("Hard")); auto item3 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Difficult"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item3->setUserObject(String::create("Difficult")); auto item4 = MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt", "Hell"), CC_CALLBACK_1(HomeWorkSnow::Start, this)); item4->setUserObject(String::create("Hell")); auto menu = Menu::create(item1, item2, item3, item4, NULL); addChild(menu); menu->alignItemsVertically();
我們要把set的數據取出來,相應的兩個函數是getUserData和getUserObject。
在菜單響應回調函數中,我們能夠例如以下操作:
void HomeWorkSnow::Start(Ref *ref) { MenuItemLabel *item = (MenuItemLabel*)ref; String * str = (String *)item->getUserObject(); auto scene = HomeWorkSnowFight::createScene(); HomeWorkSnowFight *layer = (HomeWorkSnowFight*)scene->getChildren().at(0); layer->setData(mode[str->getCString()]); Director::getInstance()->pushScene(TransitionCrossFade::create(1, scene)); }
第一步是強轉,我們用什麽類型創建的item,在回調裏我們就使用相應的類型強轉回來。
然後調用item的getUserObjet獲取set的值。
後面三句是場景的正向傳值,這個會在本篇最後講到。提前提一下,就是調用下個場景層對象的成員函數做到傳道的。
***********************************************************************************************************************************
切換場景
再創建一個新場景,然後使用以下語句加入到菜單回調函數來切換場景:
auto scene =KTWork_SwitchBg::createScene(); Director::getInstance()->replaceScene(scene);
這樣我們就實現了從一個場景切換到還有一個場景。
我們能夠在還有一個場景中盡情的加入想要的精靈。你也能夠嘗試把昨天創建的打飛機的場景加入進來。點擊菜單button就能夠開始打飛機了。
切換場景動畫
假設要使用切換的特效動畫,例如以下改動就可以:
auto scene =KTWork_SwitchBg::createScene(); Director::getInstance()->replaceScene(TransitionPageTurn::create(1,scene,true));
還有(TransitionShrinkGrow::create(1,scene)); (TransitionCrossFade::create(1, scene));等
請多嘗試幾種特效方法Transition******::create()。
假設你想返回主菜單,僅僅須要在子場景中加入一個返回的button就可以,聰明的你肯定能想到怎麽返回主菜單。
細心的話會發現切換場景的時候會提示有兩個切換方式,一種是replacescene,一種是pushscene。
這兩種切換方式的差別在於。前者釋放了當前場景,後者把當前場景壓入棧中保存。pushscene的場景要切換回來,僅僅需在子場景中調用popscene就可以。 相當於原來的場景暫停了一會。
************************************************************************************************************
場景傳值
正向傳值
我們在切換場景之前,向下一個場景傳遞參數。這個是正向傳值。
最簡單的方法就是給下一個場景的類成員變量賦值。 這樣我們就能在主場景控制我們在下一個場景想要展示的屬性。
例如以下回調函數,我們返回的場景獲取場景中全部的子節點。請右鍵查看getChildren的返回值。
由於子場景中僅僅有一個節點,所以我們第一個元素肯定是層,也就是 KTWork_PushScene類對象。然後我們能夠使用tmp來隨意正向傳遞參數給下個場景。
voidMenuScene::PushScene(Ref *ref){ this->stopAllActions(); auto scene =KTWork_PushScene::createScene(); <span style="color:#ff0000;">KTWork_PushScene * tmp = (KTWork_PushScene*)(scene->getChildren().at(0));</span> Director::getInstance()->pushScene(TransitionShrinkGrow::create(1,scene)); }
註意:我們在傳遞參數之前,KTWork_PushScene已經調用過init()函數初始化完成,那我們應該怎麽使傳遞的值生效呢?答案是使用虛函數onEnter()。onEnter是在切換場景後,展示場景前調用。所以我們能夠例如以下改動代碼:
voidHomeWork::onEnter() { <span style="color:#ff0000;"> Layer::onEnter(); //一定要先調用父類onEnter方法</span> label->setString(StringUtils::format("%s",strHp.getCString()));//這樣我們就動態改動了Label展示的值 }
在類中我們通常設變量為私有,通過get、set方法來對其訪問。在cocos2dx中,有一個宏能夠替代我們定義這兩個方法的操作。
CC_SYNTHESIZE(int, hp, HP);//定義了一個protected變量hp,定義了兩個方法setHP,getHP來獲取和設置hp的值。 CC_SYNTHESIZE(String, strHp, sHP); CC_SYNTHESIZE_RETAIN(__String *, strname, Name);//這個針對於指針變量。你如今使用可能會有崩潰的地方,這個在後面的內存管理會具體講。這個宏定義沒有想象的那麽簡單,提醒一下,要改動類的構造和析構函數。
這兩個宏大家一定要自己去看一下是怎樣定義的。
通知NotificationCenter
NotificationCenter::getInstance()->addObserver(this, callfuncO_selector(CocosStudio_SkeletonAnimate::onClick), "Ben", NULL); //收到事件之後要移除觀察者以避免內存泄露 NotificationCenter::getInstance()->postNotification("Ben", &CCString("Hello World"));
來看一下addObserver裏面的源代碼
Ref* obj = nullptr; CCARRAY_FOREACH(_observers, obj) { NotificationObserver* observer = (NotificationObserver*) obj; if (!observer) continue; if (observer->getName() == name && observer->getTarget() == target && observer->getSender() == sender) return true; }加入通知的時候會對三個參數進行推斷。也就是addObserver的第1、3、4個參數不能一樣,否則僅僅會加入一次。
最後一個參數是Ref類型的,能夠在回調函數中進行強轉。能夠對相應的Ref*進行處理,比方Label能夠對其進行改動數值等。
最後切記:記得移除觀察者(最好在onExit裏)
總結:我們學習了菜單,觸控響應,切換場景等,如今能夠做一個 例如以下的遊戲了。
有四種遊戲模式。天空會降落雪花。每一種模式雪花大小不同。 鼠標點擊能夠使雪花小時。遊戲結束返回主場景。
效果例如以下:
遊戲代碼我放到一樓去。 這些代碼我後期也在優化。
可能有一些知識點還沒有涉及到。
大家能夠用一下素材。
可能會看到我主場景有飄雪花的特效,一些煙火特效。
這些都是我復制別人的代碼實現的。有興趣的能夠自己看一下,非常easy。
cocos2dx 3.1從零學習(二)——菜單、場景切換、場景傳值