回顧一下上一篇的內容,我們已經學會了創建一個新的場景scene,添加sprite和label到層中,掌握了定時事件schedule。我們可以順利的寫出打飛機的主場景框架。
上一篇的內容我練習了七個新場景,每一個場景都展示不同的東西,像背景定時切換、各種字體的隨機顏色和位置等。每次要切換一個場景都要修改AppDelegate中的調用代碼,非常的不方便查看,這一篇我們寫場景的切換。每當我們創建一個新的場景的時候只要添加對應按鈕到主界面,點擊即可以切換過去查看對應的效果。這個有點類似官方提供的cpptest的查看方式,所以說場景切換是非常簡單易用的功能。
要點擊切換場景,必須要有按鈕可以接收消息,所以首先學習一下菜單(Menu):
Menu創建菜單
MenuItem Create 菜單子項的創建
MenuItemFont是字菜子項。
- auto item= MenuItemFont::create("Hello,Menu",CC_CALLBACK_1(MenuScene::Menutest, this));
"Hello, Menu"是菜單子項按鈕的文字。
MenuScene::Menutest是回調函數,它的參數是Menutest(Ref * pSender),這個參數類型是什麼可以通過查看create定義來獲得。
CC_CALLBACK_1就是綁定一個函數爲回調函數,_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){
- //此處可以添加一個精靈,每點擊一次菜單按鈕就添加一個精靈到場景中。
- }
還可以這樣創建一個菜單,不必每次都調用menu->addchild(item):
- 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像素
- his->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場景
上面已經介紹了菜單的創建,嘗試這去創建一個新場景吧,點擊按鈕可以切換不同的背景。
給菜單子項綁定數據
在這裏還要學習菜單子項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);
這樣我們就實現了從一個場景切換到另一個場景。
我們可以在另一個場景中盡情的添加想要的精靈,你也可以嘗試把昨天創建的打飛機的場景添加進來,點擊菜單按鈕就可以開始打飛機了!
切換場景動畫
如果要使用切換的特效動畫,如下修改即可:
- auto scene =KTWork_SwitchBg::createScene();
- Director::getInstance()->replaceScene(TransitionPageTurn::create(1,scene,true));
還有(TransitionShrinkGrow::create(1,scene)); (TransitionCrossFade::create(1, scene));等
請多嘗試幾種特效方法Transition******::create()。
如果你想返回主菜單,只需要在子場景中添加一個返回的按鈕即可,聰明的你肯定能想到怎麼返回主菜單。
細心的話會發現切換場景的時候會提示有兩個切換方式,一種是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);//這個針對於指針變量。你現在使用可能會有崩潰的地方,這個在後面的內存管理會詳細講。這個宏定義沒有想象的那麼簡單,提醒一下,要修改類的構造和析構函數。
這兩個宏大家一定要自己去看一下是如何定義的。
總結:我們學習了菜單,觸控響應,切換場景等,現在可以做一個 如下的遊戲了。
有四種遊戲模式,天空會降落雪花,每一種模式雪花大小不同。 鼠標點擊可以使雪花小時。遊戲結束返回主場景。
效果如下:
遊戲代碼我放到一樓去。 這些代碼我後期也在優化。可能有一些知識點還沒有涉及到。大家可以用一下素材。
可能會看到我主場景有飄雪花的特效,一些煙火特效。這些都是我複製別人的代碼實現的,有興趣的可以自己看一下,很簡單。