1. 程式人生 > >cocos2dx 3.1從零學習(二)——菜單、場景切換、場景傳值

cocos2dx 3.1從零學習(二)——菜單、場景切換、場景傳值

天空 ptr select 特效 new 要點 綁定 使用 water

回想一下上一篇的內容我們已經學會了創建一個新的場景scene,加入spritelabel到層中掌握了定時事件schedule。

我們能夠順利的寫出打飛機的主場景框架

上一篇的內容我練習了七個新場景每個場景都展示不同的東西像背景定時切換各種字體的隨機顏色和位置等每次要切換一個場景都要改動AppDelegate中的調用代碼很的不方便查看這一篇我們寫場景的切換每當我們創建一個新的場景的時候僅僅要加入相應button到主界面點擊即能夠切換過去查看相應的效果這個有點類似官方提供的cpptest的查看方式所以說場景切換是很easy易用的功能

要點擊切換場景必需要有button能夠接收消息

所以首先學習一下菜單Menu):

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就是綁定一個函數為回調函數

_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就加入一個精靈到場景中。

}


還能夠這樣創建一個菜單

不必每次都調用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像素
  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");
    }
}

從上面代碼能夠看到我創建了一個菜單裏面有非常多子項這些子項都是場景切換

每個新的場景都是一個練習

見效果圖:

技術分享

關於創建菜單子項還有非常多方法

MenuItemLabelMenuItemImageMenuItemSprite

以下拿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從零學習(二)——菜單、場景切換、場景傳值