Cocos2dx 3.0的回调函数

(将原文整理了格式,大神勿怪)转自: http://blog.csdn.net/crayondeng/article/details/18767407

在cocos2d-x 2.x版本中的回调函数的用法想必大家都很是熟悉,例如在menu item,call back action中都需要大量的使用到回调函数,但是在使用过程中总是感觉到比较冗余麻烦的,在3.0版本,使用到了C++11 的新特性,改进增加了回到函数的使用形式,其中最令人欣慰的是,可以使用闭包,对于有过iOS开发经验的来说,应该很亲切,就是 block。

下面将通过几个例子详细介绍在3.0版本中回调函数的各种用法。

温馨提示:由于用到了C++11中的std::function,std::bind和lambda表达式,所以对此不太了解的可以先看看我之前的这篇有关C++11的一些用法介绍 点击打开链接 。

一、通过 HelloWorldScene 中的 closeItem 开始
在cocos2d-x 2.x 版本中:

CCMenuItemImage *pCloseItem = CCMenuItemImage::create(  
                                        "CloseNormal.png",  
                                        "CloseSelected.png",  
                                        this,  
                                        menu_selector(HelloWorld::menuCloseCallback));  

在cocos2d-x 3.0 版本中:

auto closeItem = MenuItemImage::create(  "CloseNormal.png",  
                                         "CloseSelected.png",  
                                         CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); 

void HelloWorld::menuCloseCallback(Object* pSender)  
{  
    Director::getInstance()->end();  

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
    exit(0);  
#endif  
}  

注意到在3.0版本中使用到 CC_CALLBACK_1 这样一个宏定义。

// new callbacks based on C++11  
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)  
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)  
#define CC_CALCC_CALLBACK_1(HelloWorld::menuCloseCallback,this)LBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)  
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3 ##__VA_ARGS__)  

原来还有 CC_CALLBACK_0 1 2 3;而其中又有什么区别呢?

  1. 首先我们看看3.0版本中MenuItemImage的create方法:

    MenuItemImage * MenuItemImage::create(const std::string& normalImage, const std::string& selectedImage, const ccMenuCallback& callback)  
    //其中的回调参数是 ccMenuCallback 
    typedef std::function<void(Object*)> ccMenuCallback  
    //原来这里使用到了 C++ 中的 function 语法。

    注意到 在 CC_CALLBACK_ 的宏定义的中使用到的是 C++ 的 bind 语法,怎么不一致了呢? – 见下面第四点 function

  2. 看回 CC_CALLBACK_ 的宏定义
    原来 CC_CALLBACK_ 的宏定义中后面的 0 1 2 3分别表示的是 不事先指定回调函数参数的个数。
    例如说 CC_CALLBACK_ 1 表示的是,回调函数中不事先指定参数是一个,而事先指定的回调函数的参数 可以任意多个。
    而且要注意到其中 不指定回调函数参数 和 指定回调函数参数 的顺序,注意不事先指定的在前,事先指定的在后。
    下面通过例子说明这一点:
    假设回调函数:

    // a selector callback  
    void menuCloseCallback(Object* pSender,int a,int b);  
    void HelloWorld::menuCloseCallback(Object* pSender,int a,int b)  
    {  
        std::cout<<a<<"  "<<b<<std::endl;  
        Director::getInstance()->end();  
    
    
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
    
        exit(0);  
    
    #endif  
    
    }

    注意到在回调函数中输出 a b

    auto closeItem = MenuItemImage::create(  
                                               "CloseNormal.png",  
                                               "CloseSelected.png",
                                               CC_CALLBACK_1(HelloWorld::menuCloseCallback,this,1,2));  

    注意中其中 指定了两个参数 1 2

    运行,在 点击closeItem 的时候,就会输出这两个事先指定的参数 1 2。
    那么,不事先指定的参数是在什么时候传入的呢?

    void MenuItem::activate()  
    {  
        if (_enabled)  
        {  
            if( _callback )  
            {  
                _callback(this);  
            }  
    
            if (kScriptTypeNone != _scriptType)  
            {  
                BasicScriptData data(this);  
                ScriptEvent scriptEvent(kMenuClickedEvent,&data);  
                ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);  
            }  
        }  
    }  

    注意到其中的 _callback(this); 对了,这个时候就传入了 这个不事先指定的回调函数参数。

    这样,closeItem 的回调函数的 void HelloWorld::menuCloseCallback(Object* pSender,int a,int b) 的三个参数都知道了。
    第一个 不事先指定,在menu item调用 activate 的时候,_callback(this) 传入,this 也即是这个 menu item;第二、三个参数是事先指定的 1,2。

  3. bind
    已经知道 CC_CALLBACK_ 的宏定义是 std::bind 那么我们可以直接使用std::bind。
    如下:

    auto closeItem = MenuItemImage::create(  
                                               "CloseNormal.png",  
                                               "CloseSelected.png",  
                                               std::bind(&HelloWorld::menuCloseCallback, this,std::placeholders::_1,1,2));  
  4. function
    最后就解决上面的一个疑惑。

    std::function<void(Object*)> func = std::bind(&HelloWorld::menuCloseCallback,this, std::placeholders::_1,1,2);  
        auto closeItem = MenuItemImage::create(  
                                               "CloseNormal.png",  
                                               "CloseSelected.png",  
                                               func);  
  5. 使用lambda表达式

    auto closeItem = MenuItemImage::create(  
                                               "CloseNormal.png",  
                                               "CloseSelected.png",  
                                               [&](Object *sender){  
                                                   Director::getInstance()->end();  
                                                   #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)  
                                                   exit(0);  
                                                   #endif  
                                               });  

    可见使用lambda表达式可以极大的简化代码程序,不需要再定义一个回调函数,直接将在回调中的操作在闭包中体现即可。

二、在cocos2d-x中,还有一个地方是需要大量使用到回调函数的,这就是回调动作:CCCallFunc、CCCallFuncN、CCCallFuncND、CCCallFuncO。
但是这四个回调动作在 3.0 版本中已经都提示 deprecate 了。那么在3.0 版本中已经只剩下 CallFunc 和 CallFuncN.下面是官方文档中的说明:

CallFunc can be created with an std::function<void()>
CallFuncN can be created with an std::function<void(Node*)>
CallFuncND and CallFuncO were removed since it can be created with simulated with CallFuncN and CallFunc. See ActionsTest.cpp for more examples
// 其中:CallFuncND 和 CallFuncO 都可以通过 CallFunc 和 CallFuncN 进行实现。

下面通过例子详细的介绍这两个回调动作的用法。

  1. CallFunc

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

    关于CallFunc的例子,在文档中已经有体现:

        // in v2.1  
        CCCallFunc *action1 = CCCallFunc::create( this, callfunc_selector( MyClass::callback_0 ) );  
    
        // in v3.0 (short version)  
        auto action1 = CallFunc::create( CC_CALLBACK_0(MyClass::callback_0,this));  
        auto action2 = CallFunc::create( CC_CALLBACK_0(MyClass::callback_1,this, additional_parameters));  
    
        // in v3.0 (long version)  
        auto action1 = CallFunc::create( std::bind( &MyClass::callback_0, this));  
        auto action2 = CallFunc::create( std::bind( &MyClass::callback_1, this, additional_parameters));  
    
        // in v3.0 you can also use lambdas or any other "Function" object  
        auto action1 = CallFunc::create(  
                         [&](){  
                             auto s = Director::sharedDirector()->getWinSize();  
                             auto label = LabelTTF::create("called:lambda callback", "Marker Felt", 16);  
                             label->setPosition(ccp( s.width/4*1,s.height/2-40));  
                             this->addChild(label);  
                         }  );  
    
  2. CallFuncN

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

    注意到该回调动作带有一个Node*参数。
    假设回调函数:

    void ActionCallFuncN::callback(Node* sender )  
    
    auto action = Sequence::create(  
           MoveBy::create(2.0f, Point(150,0)),  
           CallFuncN::create( CC_CALLBACK_1(ActionCallFuncN::callback, this)),  
           NULL);  
    
    
    auto action = Sequence::create(  
                                       MoveBy::create(2.0f, Point(150,0)),  
                                       CallFuncN::create(std::bind(&ActionCallFuncN::callback,this,std::placeholders::_1)),  
                                       NULL);  
    
    
    auto action = Sequence::create(  
                                       MoveBy::create(2.0f, Point(150,0)),  
                                       CallFuncN::create([&](Node* sender){  
                                        //回调动作代码  
    
                                        }),  
                                       NULL);  

    受益于C++11的新语法特性 std::bind ; CallFuncND 和 CallFuncO 都可以通过 CallFunc 和 CallFuncN 进行实现

  3. CallFuncND :回调动作中带有一个Node*参数和一个void*参数
    实现过程类似于 CallFuncN
    假设回调函数是 :

    void ActionCallFuncND::doRemoveFromParentAndCleanup(Node* sender, bool cleanup)

    那么在回调动作中:

    CallFuncN::create( CC_CALLBACK_1(ActionCallFuncND::doRemoveFromParentAndCleanup, this, true))

    这样就实现了等价于 CallFuncND 的回调动作。

  4. CallFuncO :回调动作中带有一个Object*参数
    实现过程类似于 CallFunc
    假设回调函数是:

    void ActionCallFuncO::callback(Node* node, bool cleanup)

    那么在回调动作中:

    CallFunc::create( CC_CALLBACK_0(ActionCallFuncO::callback, this, _grossini, true)

    这样就实现了等价于 CallFuncO 的回调动作。

三. 总结
在新版的回调处理中,采用了C++11中的 std::function 、std::bind 、lambda 表达式,使得回调的处理变得形式多样,代码灵活了,而其中的lambda表达式可以极大的简化回调代码,推荐使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值