【cocos2d-x 3.x 学习与应用总结】4: 理解CC_CALLBACK_0, CC_CALLBACK_1, CC_CALLBACK_2, CC_CALLBACK_3

来源:互联网 发布:大数据毕业设计 编辑:程序博客网 时间:2024/06/05 04:56

前言

得益于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
  • 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++11using 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
  • 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
  • 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
  • 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
  • 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

0 0
原创粉丝点击