轉載自:http://www.cnblogs.com/C-Plus-Plus/p/4021699.html
http://demo.netfoucs.com/hanbingfengying/article/details/32936385
正向傳值:
場景A傳值到場景B景B
A.cpp
void A::onClick(CCObject * pObject)
{
// -----------------1.場景切換----------------------
CCScene * scene = B::scene();
B * layer = (B*)(scene->getChildren()->objectAtIndex(0));
layer->value = "要傳的值";
CCDirector::sharedDirector()->replaceScene(scene );
}
B.h
class B: public cocos2d::CCLayer
{
public:
virtual bool init();
virtual void onEnter();
static CCScene * scene();
CCString value;
CREATE_FUNC(B);
};
B.cpp
void B::onEnter()
{
CCLayer::onEnter();
CCLog(value.getCString());
}
反向傳值
回調函數的實作(Lambda表達式)
學習本篇前請仔細學習一下C++11的特性,std::function和lambda表達式。C++11還引入了很多boost庫的優秀代碼,使我們在使用的時候不必再加boost::,比如将要使用的std::bind;
學習位址如下:
C++11function使用
lua閉包,iosblock,C++lambda函數
簡單的說一下function的使用。統一的函數定義格式:function<int(int,float)>。就相當于一種資料類型。隻不過int是定義一個整形數,而function是定義一個函數。
view plain
copy to clipboard
print
?
- function<int(int,float)>func = [](int a ,float b){return a+b;};//定義一個函數,名為func,它的第一個形參是int,第二個形參是float,傳回值是int類型。int ret = func(3, 1.2f);
首先讓我們來看一下宏CC_CALLBACK_的定義
view plain
copy to clipboard
print
?
- // new callbacksbased on C++11#defineCC_CALLBACK_0(__selector__,__target__, ...)std::bind(&__selector__,__target__, ##__VA_ARGS__)#defineCC_CALLBACK_1(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)#defineCC_CALLBACK_2(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1,std::placeholders::_2, ##__VA_ARGS__)#defineCC_CALLBACK_3(__selector__,__target__, ...)std::bind(&__selector__,__target__, std::placeholders::_1,std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
其實它們隻是封裝了bind的用法。可以看到有幾個參數,bind後面就跟幾個_*。
要使用bind和function需要引入頭檔案#include <functional>,bind的參數類型需要引入命名空間using namespace std::placeholders;
view plain
copy to clipboard
print
?
- #include"stdafx.h"#include<iostream>#include<string>#include<functional>using namespace std;using namespacestd::placeholders; struct Foo { Foo(int num) : num_(num) {} void print_add(int i) const { std::cout<< num_ + i << '\n'; } int num_;};int _tmain(int argc,_TCHAR* argv[]){ const Foo foo(123); function<void(int)> f_add_display =bind(&Foo::print_add, foo, _1);return0;}
注意:bind要綁定一個類函數的時候,第二個參數必須是類對象。
是以我們在菜單子項綁定回調函數的時候,可以不使用CC_CALLBACK_1:
view plain
copy to clipboard
print
?
- auto item =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt",itemName->getCString())); item->setCallback(CC_CALLBACK_1(KT0618::change, this));
等價于
view plain
copy to clipboard
print
?
- auto item =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt",itemName->getCString())); item->setCallback(std::bind(&KT0618::change, this,std::placeholders::_1));
也等價于
view plain
copy to clipboard
print
?
- auto item =MenuItemLabel::create(Label::createWithBMFont("fonts/futura-48.fnt",itemName->getCString())); item->setCallback([=](Ref *ref)->void{//lambd表達式…… });
如何正确定義和聲明回調函數:
當我們create一個精靈的時候,往往記不住這種類型的精靈的回調函數有幾個參數,參數類型是什麼。這裡很重要的方法就是閱讀api。我們追蹤進去看create方法源碼,在create方法中檢視需要的回調函數傳回值是什麼類型,形參是什麼類型,複制過來即可。
在練習過程中,我們要盡量不使用CC_CALLBACK_*,而是自己書寫bind函數或者lambda表達式。
***************************************************************************************************************
反向傳值
一個簡單的應用場景:遊戲主界面展示最高分,切換到遊戲場景完成遊戲後,要向主場景傳回成績判斷是否重新整理紀錄,如果是的話就更新主界面的最高分。
前面我們學習了正向傳值,使用子場景的成員函數可以向子場景傳值。所謂反向傳值可以了解為子場景傳值回主場景。
根據我們上面學習的function,我們應該把主場景的函數指針利用子場景的成員函數傳遞給子場景存儲起來,然後在子場景中可以調用它的成員變量來調用主場景的函數。 這樣我們切換場景的時候隻能pushScene,子場景使用popScene。否則主場景的對象都不存在了還如何實作回調呢?!
新手可能會想,再在子場景中執行個體化一個主場景的類對象這麼就可以傳遞值了,然後使用replace切換場景,而不需要這麼麻煩的傳遞一個函數指針。如果按這種做法,主場景和子場景要互相引用頭檔案執行個體化對方,違反了低耦合的原則。
在子場景頭檔案中這麼定義:
view plain
copy to clipboard
print
?
- Public: std::function<void(int)> func;
我們就可以在主場景切換到子場景的時候這樣來注冊回調函數:
view plain
copy to clipboard
print
?
- auto scene =HomeWorkSnowFight::createScene();HomeWorkSnowFight*layer = (HomeWorkSnowFight*)scene->getChildren().at(0);layer->func = std::bind(&HomeWorkSnow::callback1,this,std::placeholders::_1 );//綁定回調函數到子場景Director::getInstance()->pushScene(TransitionCrossFade::create(1,scene));
這樣我們在子場景中調用func(99);就相當于調用的主場景的callback1(99)了。
三 touch事件
陀螺儀
view plain
copy to clipboard
print
?
- Device::setAccelerometerEnabled(true); // auto ac =EventListenerAcceleration::create(CC_CALLBACK_2(KT0618::accelerationc, this)); auto ac =EventListenerAcceleration::create([&](Acceleration* acc, Event* e){ sp->setPositionX(acc->x+sp->getPositionX()); }); _eventDispatcher->addEventListenerWithSceneGraphPriority(ac, this);
書寫函數的時候仔細檢視api,看create有幾個參數。
比如陀螺儀create函數的形參格式如下:
const std::function<void(Acceleration*, Event*)>& callback
這就說明需要傳入的參數應該是有兩個參數的void類型的函數對象。
陀螺儀的代碼隻能在真機上測試了。
鍵盤事件
在xcode下是無法模拟的,隻有在VS下才能測試。下面的這些代碼都是要牢記于心的,動手實作一下就明白了!
view plain
copy to clipboard
print
?
- auto keyboardLs =EventListenerKeyboard::create(); keyboardLs->onKeyPressed =[=](EventKeyboard::KeyCode code, Event*event){ if(code==EventKeyboard::KeyCode::KEY_A) { CCLOG("AAA"); } }; keyboardLs->onKeyReleased =[](EventKeyboard::KeyCode code, Event*event){ CCLOG("BBB"); }; _eventDispatcher->addEventListenerWithSceneGraphPriority(keyboardLs,this);
滑鼠事件 單點觸控
view plain
copy to clipboard
print
?
- auto listen =EventListenerTouchOneByOne::create(); listen->onTouchBegan =CC_CALLBACK_2(KT0618::onTouchBegan, this); listen->onTouchMoved =CC_CALLBACK_2(KT0618::onTouchMoved, this); listen->onTouchEnded =CC_CALLBACK_2(KT0618::onTouchEnded, this); listen->setSwallowTouches(true); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listen,this);
動手實作一下拖動一個物體到另一個物體上,隻需要拖動到目的的邊緣松開滑鼠,物體會自動放到中心處。
b
view plain
copy to clipboard
print
?
- oolKT0618::onTouchBegan(Touch *t, Event*e){ Point p = t->getLocation(); Rect rect = spMove->getBoundingBox(); if (rect.containsPoint(p)) { return true; } else { return false; } return true;}voidKT0618::onTouchMoved(Touch *t, Event*e){ Point p = t->getLocation(); Rect rect = spMove->getBoundingBox(); if (rect.containsPoint(p)) { spMove->setPosition(p); }} voidKT0618::onTouchEnded(Touch *t, Event*e){ Point p = t->getLocation(); Rect rect = spBase->getBoundingBox(); if (rect.containsPoint(p)) { spMove->setPosition(spBase->getPosition()); }}
多點觸控
ios下AppController.mm加一句[eaglView setMultipleTouchEnabled:YES];在模拟器按住alt可以調試多點。
windows就不用想了,surface除外。
view plain
copy to clipboard
print
?
- auto touchMore =EventListenerTouchAllAtOnce::create(); touchMore->onTouchesBegan =CC_CALLBACK_2(KT0618::onTouchesBegan, this); touchMore->onTouchesMoved =CC_CALLBACK_2(KT0618::onTouchesMoved, this); touchMore->onTouchesEnded =CC_CALLBACK_2(KT0618::onTouchesEnded, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchMore,this);
onTouchesBegan跟單點觸控傳回值不同,請具體的根據api來寫。
view plain
copy to clipboard
print
?
- void KT0618::onTouchesBegan(conststd::vector<Touch*>& touches, Event* events){ for (auto v : touches ) { v->getLocation(); }}voidKT0618::onTouchesMoved(const std::vector<Touch*>& touches, Event*unused_event){}void KT0618::onTouchesEnded(conststd::vector<Touch*>& touches, Event *unused_event){}
添加自定義消息響應EventListenerCustom
init()裡面添加如下代碼,那麼這個層就會響應标志位shutdown的消息。
view plain
copy to clipboard
print
?
- auto listenCustom =EventListenerCustom::create("shutdown",CC_CALLBACK_1(KT0618::popupLayerCustom, this)); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listenCustom,1);
這樣可以在需要發送shutdown消息的地方這樣添加,第二個參數是這條消息的自定義參數。
_eventDispatcher->dispatchCustomEvent("shutdown", (void*)"Go!DongGuan!");
這樣就往外分發了一個名字是shutdown的消息。
這個消息可以在不同的層中接收到,利用第二個參數可以做到資料傳遞。可以是任何類型的資料,比回調友善。
其他層init也照上面添加,并添加對應的響應函數。
view plain
copy to clipboard
print
?
- voidPopupLayer::shutdown(EventCustom * event){ char * str =(char *)event->getUserData(); CCLOG("Do not toucheme,bullshit!"); CCLOG(str);}
添加音效
#include<SimpleAudioEngine.h>
usingnamespace CocosDenshion;
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(MUSIC_BG,true);
CocosDenshion:
:SimpleAudioEngine::sharedEngine()->playEffect(MUSIC_ENEMY1);
音效init的時候預加載,但是要注意切換場景的時候要釋放掉預加載的音效。
view plain
copy to clipboard
print
?
- CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic(MUSIC_BG);CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect(MUSIC_BULLET);