加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Cocos2d-x 3.0 新特性体验- 回调函数的变化

发布时间:2020-12-14 19:37:45 所属栏目:百科 来源:网络整理
导读:在cocos2d-x 2.x版本中的回调函数的用法想必大家都很是熟悉,例如在menu item,call back action中都需要大量的使用到回调函数,但是在使用过程中总是感觉到比较冗余麻烦的,在3.0版本,使用到了C++11 的新特性,改进增加了回到函数的使用形式,其中最令人欣

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

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

一、通过 HelloWorldScene 中的 closeItem 开始

在cocos2d-x 2.x 版本中:

[cpp] view plain copy
  1. CCMenuItemImage*pCloseItem=CCMenuItemImage::create(
  2. "CloseNormal.png",
  3. "CloseSelected.png",
  4. this,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> menu_selector(HelloWorld::menuCloseCallback));

在cocos2d-x 3.0 版本中:

    autocloseItem=MenuItemImage::create(
  1. CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));

    voidHelloWorld::menuCloseCallback(Object*pSender)
  1. {
  2. Director::getInstance()->end();
  3. #if(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)
  4. exit(0);
  5. #endif
  6. }

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

    //newcallbacksbasedonC++11
  1. #defineCC_CALLBACK_0(__selector__,__target__,...)std::bind(&__selector__,##__VA_ARGS__)
  2. #defineCC_CALLBACK_1(__selector__,std::placeholders::_1,##__VA_ARGS__)
  3. #defineCC_CALCC_CALLBACK_1(HelloWorld::menuCloseCallback,this)LBACK_2(__selector__,std::placeholders::_2,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> #defineCC_CALLBACK_3(__selector__,std::placeholders::_3##__VA_ARGS__)

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

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

    MenuItemImage*MenuItemImage::create(conststd::string&normalImage,conststd::string&selectedImage,153); font-weight:bold; background-color:inherit">constccMenuCallback&callback)
其中的回调参数是 ccMenuCallback

    typedefstd::function<void(Object*)>ccMenuCallback
原来这里使用到了 C++ 中的 function 语法。

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


2、看回CC_CALLBACK_ 的宏定义

原来CC_CALLBACK_ 的宏定义中后面的 0 1 2 3分别表示的是 不事先指定回调函数参数的个数。

例如说CC_CALLBACK_ 1 表示的是,回调函数中不事先指定参数是一个,而事先指定的回调函数的参数 可以任意多个

而且要注意到其中 不指定回调函数参数 和 指定回调函数参数 的顺序,注意不事先指定的在前,事先指定的在后

下面通过例子说明这一点:

假设回调函数:

    //aselectorcallback
  1. voidmenuCloseCallback(Object*pSender,inta,87); font-weight:bold; background-color:inherit">intb);


    voidHelloWorld::menuCloseCallback(Object*pSender,87); font-weight:bold; background-color:inherit">intb)
  1. std::cout<<a<<""<<b<<std::endl;
  2. Director::getInstance()->end();
  3. #if(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)
  4. exit(0);
  5. #endif
  6. }
注意到在回调函数中输出 a b

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

    运行,在 点击closeItem 的时候,就会输出这两个事先指定的参数 1 2。

    那么,不事先指定的参数是在什么时候传入的呢?

      voidMenuItem::activate()
    1. if(_enabled)
    2. if(_callback)
    3. _callback(this);
    4. }
    5. if(kScriptTypeNone!=_scriptType)
    6. {
    7. BasicScriptDatadata(this);
    8. ScriptEventscriptEvent(kMenuClickedEvent,&data);
    9. ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
    10. }
    11. }
    注意到其中的 _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。

    如下:

      std::bind(&HelloWorld::menuCloseCallback,2));

    4、function

    最后就解决上面的一个疑惑。

      std::function<void(Object*)>func=std::bind(&HelloWorld::menuCloseCallback,2);
    1. autocloseItem=MenuItemImage::create(
    2. "CloseNormal.png",248)"> "CloseSelected.png",108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> func);

    5、使用lambda表达式

      [&](Object*sender){
    1. });
    可见使用lambda表达式可以极大的简化代码程序,不需要再定义一个回调函数,直接将在回调中的操作在闭包中体现即可。


    二、在cocos2d-x中,还有一个地方是需要大量使用到回调函数的,这就是回调动作:CCCallFunc、CCCallFuncN、CCCallFuncND、CCCallFuncO。

    但是这四个回调动作在 3.0 版本中已经都提示 deprecate 了。那么在3.0 版本中已经只剩下CallFunc 和 CallFuncN.

    下面是官方文档中的说明:

    • CallFunccan be created with anstd::function<void()>
    • CallFuncNcan be created with anstd::function<void(Node*)>
    • CallFuncNDandCallFuncOwere removed since it can be created with simulated withCallFuncNandCallFunc. See ActionsTest.cpp for more examples
    其中:CallFuncND 和 CallFuncO 都可以通过CallFunc 和 CallFuncN 进行实现。

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

    1、CallFunc

      staticCallFunc*create(conststd::function<void()>&func);

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

      //inv2.1
    1. CCCallFunc*action1=CCCallFunc::create( //inv3.0(shortversion)
    2. autoaction1=CallFunc::create(CC_CALLBACK_0(MyClass::callback_0,153); font-weight:bold; background-color:inherit">this));
    3. autoaction2=CallFunc::create(CC_CALLBACK_0(MyClass::callback_1,additional_parameters));
    4. //inv3.0(longversion)
    5. autoaction1=CallFunc::create(std::bind(&MyClass::callback_0,248)"> autoaction2=CallFunc::create(std::bind(&MyClass::callback_1,0); background-color:inherit">//inv3.0youcanalsouselambdasoranyother"Function"object
    6. autoaction1=CallFunc::create(
    7. [&](){
    8. autos=Director::sharedDirector()->getWinSize();
    9. autolabel=LabelTTF::create("called:lambdacallback","MarkerFelt",16);
    10. label->setPosition(ccp(s.width/4*1,s.height/2-40));
    11. this->addChild(label);
    12. });


    2、CallFuncN

      staticCallFuncN*create(void(Node*)>&func);

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

    假设回调函数:

      voidActionCallFuncN::callback(Node*sender)


      autoaction=Sequence::create(
    1. MoveBy::create(2.0f,Point(150,0)),
    2. CallFuncN::create(CC_CALLBACK_1(ActionCallFuncN::callback,153); font-weight:bold; background-color:inherit">this)),248)"> NULL);

      CallFuncN::create(std::bind(&ActionCallFuncN::callback,std::placeholders::_1)),160); text-decoration:none; border:none; padding:1px; margin:0px 10px 0px 0px; font-size:9px; display:inline-block; width:16px; height:16px; text-indent:-2000px; background-color:inherit" rel="nofollow">
        CallFuncN::create([&](Node*sender){
      1. //回调动作代码
      2. }),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> 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,_grossini,true)

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


      三、总结

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

      (编辑:李大同)

      【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读