2017年6月3日 星期六

0603 cocos2dx 3.0 之 用std::bind替換CC_CALLBACK_N

http://www.cnblogs.com/fzll/p/3954604.html



在cocos2dx 3.0 版本中,回調函數基本上由4個CC_CALLBACK_N 函數代替,N代表回調函數的參數個數

1.先讓我們來看看這些CC_CALLBACK_N怎麼用


比如action的回調 ,CC_CALLBACK_0

  1. auto animation = Animation::create();  
  2. auto animate = Animate::create(animation);  
  3. CallFunc* animateDone = CallFunc::create(CC_CALLBACK_0(PlaneLayer::removePlane,this));  
  4. auto sequence = Sequence::create(animate,animateDone,NULL);  
  5. sprite1->runAction(sequence);  
  6.   
  7. void PlaneLayer::removePlane(){  
  8.     //.....  
  9. }  

或者action帶一個參數的回調:CC_CALLBACK_1,在這裡,pSender就是動作的執行者sprite2

  1. auto actionMove = MoveTo::create(randomDuration, Point(0, 0));  
  2. auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::enemy1MoveFinished,this));  
  3. auto sequence = Sequence::create(actionMove,actionDone,NULL);  
  4. sprite2->runAction(sequence);  
  5.   
  6. void EnemyLayer::enemy1MoveFinished(Node* pSender){  
  7.     Sprite* sprite2 = (Sprite*)pSender;  
  8. }  


或者按鈕的回調函數:CC_CALLBACK_1

  1. auto pauseNormal = Sprite::create("game_pause_nor.png");  
  2. auto pausePressed = Sprite::create("game_pause_pressed.png");  
  3.       
  4. auto menuItem = MenuItemSprite::create(pauseNormal,pausePressed,NULL,CC_CALLBACK_1(ControlLayer::menuPauseCallback,this));  
  5. menuItem->setPosition(Point::ZERO);  
  6. auto menuPause = Menu::create(menuItem,NULL);  
  7. menuPause->setPosition(Point::ZERO);  
  8.   
  9. //回調函數  
  10. void ControlLayer::menuPauseCallback(Object* pSender)  
  11. {  
  12.     //....  
  13. }  

或者touch函數:CC_CALLBACK_2

  1. //單點觸摸    
  2. virtual bool onTouchBegan(Touch *touch, Event *unused_event);     
  3. virtual void onTouchMoved(Touch *touch, Event *unused_event);     
  4. virtual void onTouchEnded(Touch *touch, Event *unused_event);     
  5. virtual void onTouchCancelled(Touch *touch, Event *unused_event);  
  6.   
  7.   
  8. auto dispatcher = Director::getInstance()->getEventDispatcher();  
  9. auto listener = EventListenerTouchOneByOne::create();  
  10. listener->onTouchBegan = CC_CALLBACK_2(GameLayer::onTouchBegan,this);  
  11. listener->onTouchMoved = CC_CALLBACK_2(GameLayer::onTouchMoved,this);  
  12. listener->onTouchEnded = CC_CALLBACK_2(GameLayer::onTouchEnded,this);  
  13. listener->setSwallowTouches(true);//不向下傳遞觸摸  
  14. dispatcher->addEventListenerWithSceneGraphPriority(listener,this);  



2.發現了上面的CallFunc和CallFucnN了沒有,恩,先去LOL一把再接著寫。。


回來了。讓我先回口血,恩,接著寫...

一般來說:

CallFunc用於 不帶參數的
CallFuncN 用於創建 帶一個Node節點參數的,Node*節點參數是動作的執行者
CCCallFuncND 比CallFuncN多了一個參數,可以是任意類型的參數  void *,用法看下面

  1. auto animation = AnimationCache::getInstance()->animationByName("Enemy1Blowup");  
  2. auto animate = Animate::create(animation);  
  3. CCCallFuncND* animateDone = CCCallFuncND::create(this,callfuncND_selector(EnemyLayer::removeEnemy1),(void*)enemy1);  
  4. auto sequence = Sequence::create(animate, animateDone,NULL);  
  5. Sprite* m_sprite = enemy1->getSprite();  
  6. m_sprite ->runAction(sequence);  
  7.   
  8.   
  9. void EnemyLayer::removeEnemy1(Node* pTarget, void* data){  
  10.     Sprite* m_sprite = (Sprite*) pTarget; //node節點為動作的執行者  
  11.     Enemy* enemy1 = (Enemy*)data;         //我們傳的自定義數據enemy1  
  12.     //...  
  13. }  

其實上面調用帶兩個參數的函數的這句代碼:
  1. CCCallFuncND* animateDone = CCCallFuncND::create(this,callfuncND_selector(EnemyLayer::removeEnemy1),(void*)enemy1);  

我們還可以這樣子寫:
  1. //寫法1  
  2. CCCallFuncN* animateDone = CCCallFuncN::create(CC_CALLBACK_1(EnemyLayer::removeEnemy1,this,enemy1));  
  3. //寫法2  
  4. CCCallFunc* animateDone = CCCallFunc::create(CC_CALLBACK_0(EnemyLayer::removeEnemy1,this,enemy1->getSprite(),enemy1));  
  5. //寫法3,用std::bind  
  6. CCCallFuncN* animateDone = CCCallFuncN::create(std::bind(&EnemyLayer::removeEnemy1,this,enemy1->getSprite(),enemy1));  


其實上面的CC_CALLBACK_0 啊CC_CALLBACK_1 啊,都可以類似這麼寫,很多種寫法,原因是因為CC_CALLBACK_N有一個可變參數宏##__VA_ARGS__

恩,是不是有點亂,記不住沒關係,我也經常沒記住,我們來具體看一下CC_CALLBACK_N到底是神馬玩意

  1. // new callbacks based on C++11  
  2. #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)  
  3. #define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)  
  4. #define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)  
  5. #define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ##__VA_ARGS__)  

是不是看到了std::bind、##__VA_ARGS__、std::placeholders::_1等等,這些都是神馬玩意,


先解釋一下:

##__VA_ARGS__是可變參數宏
std::placeholders::_1是參數佔位符,表示第一個參數,以此類推



那std::bind是神馬,不急我們先看一段代碼

  1. #include <iostream>  
  2. #include <functional>  
  3. using namespace std;  
  4.   
  5. typedef std::function<void ()> fp;  
  6. void g_fun()  
  7. {  
  8.     cout<<"g_fun()"<<endl;  
  9. }  
  10. class A  
  11. {  
  12. public:  
  13.     static void A_fun_static()  
  14.     {  
  15.         cout<<"A_fun_static()"<<endl;  
  16.     }  
  17.     void A_fun()  
  18.     {  
  19.         cout<<"A_fun()"<<endl;  
  20.     }  
  21.     void A_fun_int(int i)  
  22.     {  
  23.         cout<<"A_fun_int() "<<i<<endl;  
  24.     }  
  25.   
  26.     void A_fun_int_double(int i,int p)  
  27.     {  
  28.         cout<<"A_fun_int_double ()"<<i<<","<<p<<endl;  
  29.     }  
  30.   
  31.     //非靜態類成員,因為含有this指針,所以需要使用bind  
  32.     void init()  
  33.     {  
  34.         //綁定不帶參數的函數  
  35.         fp fp1=std::bind(&A::A_fun,this);  
  36.         fp1();  
  37.     }  
  38.   
  39.     void init2()  
  40.     {  
  41.         typedef std::function<void (int)> fpi;  
  42.         //綁定帶一個參數的函數  
  43.         fpi f=std::bind(&A::A_fun_int,this,std::placeholders::_1);//參數要使用佔位符 std::placeholders::_1表示第一個參數  
  44.         f(5);  
  45.     }  
  46.   
  47.     void init3(){  
  48.         typedef std::function<void (int,double)> fpid;  
  49.         //綁定帶兩個參數的函數  
  50.         fpid f=std::bind(&A::A_fun_int_double,this,std::placeholders::_1,std::placeholders::_2);  
  51.         f(5,10);  
  52.     }  
  53. };  
  54. int main()  
  55. {  
  56.     //綁定到全局函數  
  57.     fp f2=fp(&g_fun);  
  58.     f2();  
  59.   
  60.     //綁定到類靜態成員函數  
  61.     fp f1=fp(&A::A_fun_static);  
  62.     f1();  
  63.   
  64.     A().init();  
  65.     A().init2();  
  66.     A().init3();  
  67.     return 0;  
  68. }  

然後看一下輸出結果:
  1. g_fun()  
  2. A_fun_static()  
  3. A_fun()  
  4. A_fun_int() 5  
  5. A_fun_int_double ()5,10  

再解釋一下:
std::function  --> 綁定到全局函數/類靜態成員函數(類靜態成員函數與全局函數沒有區別)
std::bind       --> 綁定到類的非靜態成員函數

到這裡是不是有豁然開朗的感覺呢,哈哈,知道了bind函數怎麼用,然後我們就可以使用std::bind替換CC_CALLBACK_N寫法了

3.使用std:bind函數替換CC_CALLBACK_N:



比如我們要替換CC_CALLBACK_0

  1. auto animation = Animation::create();  
  2. auto animate = Animate::create(animation);  
  3. //CallFunc* animateDone = CallFunc::create(CC_CALLBACK_0(PlaneLayer::removePlane,this));  
  4. CallFunc* animateDone = CallFunc::create(std::bind(&PlaneLayer::removePlane,this));//替換  
  5. auto sequence = Sequence::create(animate,animateDone,NULL);  
  6. sprite1->runAction(sequence);  
  7.   
  8. void PlaneLayer::removePlane(){  
  9.     //.....  
  10. }  


比如我們要替換帶一個參數的CC_CALLBACK_1

  1. auto actionMove = MoveTo::create(randomDuration, Point(0, 0));  
  2. //auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::enemy1MoveFinished,this));  
  3. auto actionDone = CallFuncN::create(std::bind(&EnemyLayer::enemy1MoveFinished,this,enemy1));//替換  
  4. auto sequence = Sequence::create(actionMove,actionDone,NULL);  
  5. sprite2->runAction(sequence);  
  6.   
  7. void EnemyLayer::enemy1MoveFinished(Node* pSender){  
  8.     Sprite* sprite2 = (Sprite*)pSender;  
  9. }  

再比如調用兩個參數的...

  1. auto animation = AnimationCache::getInstance()->animationByName("Enemy1Blowup");  
  2. auto animate = Animate::create(animation);  
  3. //CCCallFuncND* animateDone = CCCallFuncND::create(this,callfuncND_selector(EnemyLayer::removeEnemy1),(void*)enemy1);  
  4. CCCallFuncN* animateDone = CCCallFuncN::create(std::bind(&EnemyLayer::removeEnemy1,this,enemy1->getSprite(),enemy1));//替換  
  5. auto sequence = Sequence::create(animate, animateDone,NULL);  
  6. Sprite* m_sprite = enemy1->getSprite();  
  7. m_sprite ->runAction(sequence);  
  8.   
  9.   
  10. void EnemyLayer::removeEnemy1(Node* pTarget, void* data){  
  11.     Sprite* m_sprite = (Sprite*) pTarget; //node節點為動作的執行者  
  12.     Enemy* enemy1 = (Enemy*)data;         //我們傳的自定義數據enemy1  
  13.     //...  
  14. }  


哈哈,這下子很清楚了吧。。再也不會混亂了。。

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

重要關鍵字  EVENT_MOUSE_SCROLL addEventListenerWithSceneGraphPriority      if IsPc() then --建立滑鼠監聽         local listener = cc.EventListenerMouse...