【cocos2d-x 3.x 學習與應用總結】4: 理解CC_CALLBACK_0, CC_CALLBACK_1, CC_CALLBACK_2, CC_CALLBACK_3

前言

得益於C++11的新特性,cocos 3.x版本在很多地方的代碼看起來都優美了許多。這其中就包括一些回調函數的寫法,CC_CALLBACK_N系列宏的作用是對一個成員函數進行適配並返回一個回調函數。本文介紹一下我對CC_CALLBACK_N系列宏的理解。

使用CC_CALLBACK_N的例子

下面這段代碼來自cocos官方示例中的ActionTest.cpp, 這是在創建一個CallFunc的回調。

使用CC_CALLBACK_0來代替其原來的創建回調的方式:

使用CC_CALLBACK_0來改寫上面三個回調的創建:

auto action1 = Sequence::create(
                        MoveBy::create(2, Vec2(200,0)),
                        //CallFunc::create(std::bind(&ActionCallFunction::callback1, this)), 原來的方式
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback1, this)),
                        CallFunc::create(
                             // lambda
                             [&](){
                                 auto s = Director::getInstance()->getWinSize();
                                 auto label = Label::createWithTTF("called:lambda callback", "fonts/Marker Felt.ttf", 16.0f);
                                 label->setPosition(s.width/4*1,s.height/2-40);
                                 this->addChild(label);
                             }  ),
                        nullptr);

    auto action2 = Sequence::create(
                        ScaleBy::create(2 ,  2),
                        FadeOut::create(2),
                        //CallFunc::create(std::bind(&ActionCallFunction::callback2, this, _tamara)), 原來的方式
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback2, this, _tamara)),
                        nullptr);

    auto action3 = Sequence::create(
                        RotateBy::create(3 , 360),
                        FadeOut::create(2),
                        //CallFunc::create(std::bind(&ActionCallFunction::callback3, this, _kathia, 42)), 原來的方式
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback3, this, _kathia, 42)),
                        nullptr);

void ActionCallFunction::callback1()
{
    auto s = Director::getInstance()->getWinSize();
    auto label = Label::createWithTTF("callback 1 called", "fonts/Marker Felt.ttf", 16.0f);
    label->setPosition(s.width/4*1,s.height/2);

    addChild(label);
}

void ActionCallFunction::callback2(Node* sender)
{
    auto s = Director::getInstance()->getWinSize();
    auto label = Label::createWithTTF("callback 2 called", "fonts/Marker Felt.ttf", 16.0f);
    label->setPosition(s.width/4*2,s.height/2);

    addChild(label);

    CCLOG("sender is: %p", sender);
}

void ActionCallFunction::callback3(Node* sender, long data)
{
    auto s = Director::getInstance()->getWinSize();
    auto label = Label::createWithTTF("callback 3 called", "fonts/Marker Felt.ttf", 16.0f);
    label->setPosition(s.width/4*3,s.height/2);
    addChild(label);

    CCLOG("target is: %p, data is: %ld", sender, data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

如何理解CC_CALLBACK_0CC_CALLBACK_1CC_CALLBACK_2CC_CALLBACK_3

這個CC_CALLBACK_0其實就是std::bind,下面是它和它的小夥伴們:

defined in ccMacro.h


// new callbacks based on C++11

using std::bind;
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;

#define CC_CALLBACK_0(__selector__,__target__, ...) bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) bind(&__selector__,__target__, _1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) bind(&__selector__,__target__, _1, _2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) bind(&__selector__,__target__, _1, _2, _3, ##__VA_ARGS__)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

爲了讓這幾個宏看起來更清晰,在上面我使用了using聲明整理了一下代碼。

這四個宏的作用都是用來適配函數,把一個原始函數A,包裝成函數B。這裏面的A需要是一個類的成員函數,其中的:

__selector__就是這個成員函數,比如MyClass::func;

__target__是MyClass類型的一個對象(或者是對象的引用和指針,比如最常見的this)

其它的參數,或者是佔位符(_1, _2, _3)或者是具體的參數,具體的細節請參考我的這篇【C++ STL學習與應用總結】22: 函數組合之1:如何使用std::bind.

如何理解這幾個參數的命名呢?爲什麼是0, 1, 2, 3?

是這樣的,結尾的數字N,代表者CC_CALLBACK_N這個宏返回的結果是一個需要N個參數的函數。

  • CC_CALLBACK_<font color="red">0</font> 意思就是返回一個需要0個參數方可調用的函數, 也就是說不需要參數就能調用的函數

  • CC_CALLBACK_<font color="red">1</font> 意思就是返回一個需要1個參數方可調用的函數

  • CC_CALLBACK_<font color="red">2</font> 意思就是返回一個需要2個參數方可調用的函數

  • CC_CALLBACK_<font color="red">3</font> 意思就是返回一個需要3個參數方可調用的函數

這裏需要的參數個數其實也就是佔位符的個數(_1, _2, _3), 佔位符是需要在函數調用的時候用具體的實參來替換的。

這樣理解了之後,就很容易知道什麼時候該用哪個宏了。

比如,我要創建一個CallFunc, static CallFunc * create(const std::function<void()>& func);, 從其聲明可以看出它需要一個不用參數就能調用的函數,那麼我就可以用CC_CALLBACK_0

auto action2 = Sequence::create(
                        ScaleBy::create(2 ,  2),
                        FadeOut::create(2),
                        //CallFunc::create(std::bind(&ActionCallFunction::callback2, this, _tamara)), 原來的方式
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback2, this, _tamara)),
                        nullptr);

void ActionCallFunction::callback2(Node* sender)
{
    auto s = Director::getInstance()->getWinSize();
    auto label = Label::createWithTTF("callback 2 called", "fonts/Marker Felt.ttf", 16.0f);
    label->setPosition(s.width/4*2,s.height/2);

    addChild(label);

    CCLOG("sender is: %p", sender);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

即使callback2接收N個參數,我也可以使用CC_CALLBACK_0來把它適配成一個不需要參數就能調用的函數。這是std::bind的工作方式決定的,我只需把callback2需要的參數填入CC_CALLBACK_0裏面就好。

auto action2 = Sequence::create(
                        ScaleBy::create(2 ,  2),
                        FadeOut::create(2),
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback5, this, 100, 200, 11, 12, 23)),
                        nullptr);

void ActionCallFunction::callback5(int i1, int i2, int i3, int i4, int i5)
{
    // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CC_CALLBACK_1在CallFuncN::create中的使用

CallFuncN::create的原型:

static CallFuncN * create(const std::function<void(Node*)>& func);

從create的參數可以看到,它需要一個“需要一個Node*參數的參數方可調用的函數”, 這剛好和前面講到的CC_CALLBACK_1的作用一樣。

void ActionCallFuncND::onEnter()
{
    // ActionCallFuncND::doRemoveFromParentAndCleanup本來是需要兩個參數:(Node*, bool), 使用CC_CALLBACK_1把第二個參數綁定爲true,
    // 這樣就變成了一個僅需要一個Node*參數的函數。
    auto action = Sequence::create(
        MoveBy::create(2.0f, Vec2(200,0)),
        CallFuncN::create( CC_CALLBACK_1(ActionCallFuncND::doRemoveFromParentAndCleanup, this, true)),
        nullptr);

    // 這是action的等價定義,可以看到佔位符_1頂替了Node*的位置。
    auto action2 = Sequence::create(
        MoveBy::create(2.0f, Vec2(200, 0)),
        CallFuncN::create(std::bind(&ActionCallFuncND::doRemoveFromParentAndCleanup, this, std::placeholders::_1, true)),
        nullptr);

    _grossini->runAction(action2);
}

void ActionCallFuncND::doRemoveFromParentAndCleanup(Node* sender, bool cleanup)
{
    _grossini->removeFromParentAndCleanup(cleanup);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

CC_CALLBACK_2CC_CALLBACK_3的使用方式與此類似,不再贅述。


原文地址:http://blog.csdn.net/elloop/article/details/50445722

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章