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

前端之家收集整理的这篇文章主要介绍了【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@H_502_5@系列宏的作用是对一个成员函数进行适配并返回一个回调函数。本文介绍一下我对CC_CALLBACK_N@H_502_5@系列宏的理解。

使用CC_CALLBACK_N@H_502_5@的例子

下面这段代码来自cocos官方示例中的ActionTest.cpp,这是在创建一个CallFunc的回调。

使用CC_CALLBACK_0@H_502_5@来代替其原来的创建回调的方式:

使用CC_CALLBACK_0@H_502_5@来改写上面三个回调的创建:

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,nullptr);

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

void ActionCallFunction::callback1()
{
    auto s = Director::getInstance()->getWinSize();
    auto label = Label::createWithTTF("callback 1 called",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",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",16.0f);
    label->setPosition(s.width/4*3,s.height/2);
    addChild(label);

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

如何理解CC_CALLBACK_0@H_502_5@,CC_CALLBACK_1@H_502_5@,CC_CALLBACK_2@H_502_5@,CC_CALLBACK_3@H_502_5@

这个CC_CALLBACK_0@H_502_5@其实就是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__,##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,_1,##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,_2,##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,_3,##__VA_ARGS__)

为了让这几个宏看起来更清晰,在上面我使用了using声明整理了一下代码

这四个宏的作用都是用来适配函数,把一个原始函数A,包装成函数B。这里面的A需要是一个类的成员函数,其中的:

__selector__@H_502_5@就是这个成员函数,比如MyClass::func;

__target__@H_502_5@是MyClass类型的一个对象(或者是对象的引用和指针,比如最常见的this)

其它的参数,或者是占位符(_1,_3@H_502_5@)或者是具体的参数,具体的细节请参考我的这篇【C++ STL学习与应用总结】22: 函数组合之1:如何使用std::bind.

如何理解这几个参数的命名呢?为什么是0,1,2,3?

是这样的,结尾的数字N,代表者CC_CALLBACK_N@H_502_5@这个宏返回的结果是一个需要N个参数的函数

  • CC_CALLBACK_<font color="red">0</font>@H_502_5@ 意思就是返回一个需要0个参数方可调用函数,也就是说不需要参数就能调用函数

  • CC_CALLBACK_<font color="red">1</font>@H_502_5@ 意思就是返回一个需要1个参数方可调用函数

  • CC_CALLBACK_<font color="red">2</font>@H_502_5@ 意思就是返回一个需要2个参数方可调用函数

  • CC_CALLBACK_<font color="red">3</font>@H_502_5@ 意思就是返回一个需要3个参数方可调用函数

这里需要的参数个数其实也就是占位符的个数(_1,_3@H_502_5@),占位符是需要在函数调用的时候用具体的实参来替换的。

这样理解了之后,就很容易知道什么时候该用哪个宏了。

比如,我要创建一个CallFunc,static CallFunc * create(const std::function<void()>& func);@H_502_5@,从其声明可以看出它需要一个不用参数就能调用函数,那么我就可以用CC_CALLBACK_0@H_502_5@。

auto action2 = Sequence::create(
                        ScaleBy::create(2,FadeOut::create(2),原来的方式
                        CallFunc::create(CC_CALLBACK_0(ActionCallFunction::callback2,nullptr);

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

    addChild(label);

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

即使callback2接收N个参数,我也可以使用CC_CALLBACK_0@H_502_5@来把它适配成一个不需要参数就能调用函数。这是std::bind的工作方式决定的,我只需把callback2需要的参数填入CC_CALLBACK_0@H_502_5@里面就好。

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

void ActionCallFunction::callback5(int i1,int i2,int i3,int i4,int i5)
{
    // ...
}

CC_CALLBACK_1@H_502_5@在CallFuncN::create中的使用

CallFuncN::create的原型:

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

从create的参数可以看到,它需要一个“需要一个Node*参数的参数方可调用函数”, 这刚好和前面讲到的CC_CALLBACK_1@H_502_5@的作用一样。

void ActionCallFuncND::onEnter()
{
    // ActionCallFuncND::doRemoveFromParentAndCleanup本来是需要两个参数:(Node*,bool),使用CC_CALLBACK_1把第二个参数绑定为true,
    // 这样就变成了一个仅需要一个Node*参数的函数
    auto action = Sequence::create(
        MoveBy::create(2.0f,CallFuncN::create( CC_CALLBACK_1(ActionCallFuncND::doRemoveFromParentAndCleanup,true)),nullptr);

    // 这是action的等价定义,可以看到占位符_1顶替了Node*的位置。
    auto action2 = Sequence::create(
        MoveBy::create(2.0f,CallFuncN::create(std::bind(&ActionCallFuncND::doRemoveFromParentAndCleanup,std::placeholders::_1,nullptr);

    _grossini->runAction(action2);
}

void ActionCallFuncND::doRemoveFromParentAndCleanup(Node* sender,bool cleanup)
{
    _grossini->removeFromParentAndCleanup(cleanup);
}

CC_CALLBACK_2@H_502_5@,CC_CALLBACK_3@H_502_5@的使用方式与此类似,不再赘述。


作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!

在这里也能看到这篇文章github博客,CSDN博客,欢迎访问

猜你在找的Cocos2d-x相关文章