`
jiapumin
  • 浏览: 344406 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

 
阅读更多

在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 版本中:

1
2
3
4
5
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback));

 

在cocos2d-x 3.0 版本中:

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

 

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


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

 

 

1
2
3
4
5
// 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方法:

 

1
MenuItemImage * MenuItemImage::create(const std::string& normalImage, const std::string& selectedImage, const ccMenuCallback& callback)

其中的回调参数是 ccMenuCallback

 

 

1
typedef std::function<void(object*)> ccMenuCallback</void(object*)>

原来这里使用到了 C++ 中的 function 语法。

 

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

 

2、看回 CC_CALLBACK_ 的宏定义

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

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

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

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

假设回调函数:

 

1
2
// a selector callback
    void menuCloseCallback(Object* pSender,int a,int b);

 

 

1
2
3
4
5
6
7
8
void HelloWorld::menuCloseCallback(Object* pSender,int a,int b)
{
    std::cout<end();
 
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}</a<<">

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

 

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

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

 

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

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。

如下:

 

1
2
3
4
auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           std::bind(&HelloWorld::menuCloseCallback, this,std::placeholders::_1,1,2));

 

 

4、function

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

 

1
2
3
4
5
6
std::function<void(object*)> func = std::bind(&HelloWorld::menuCloseCallback,this, std::placeholders::_1,1,2);
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           func);
</void(object*)>


5、使用lambda表达式

 

 

1
2
3
4
5
6
7
8
9
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 withCallFuncN and CallFunc. See ActionsTest.cpp for more examples 其中:CallFuncND 和 CallFuncO 都可以通过 CallFunc 和 CallFuncN 进行实现。

     

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

    1、CallFunc

     

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

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

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 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

     

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

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

    假设回调函数:

     

    1
    void ActionCallFuncN::callback(Node* sender )

     

     

    1
    2
    3
    4
    auto action = Sequence::create(
           MoveBy::create(2.0f, Point(150,0)),
           CallFuncN::create( CC_CALLBACK_1(ActionCallFuncN::callback, this)),
           NULL);
     
    1
    2
    3
    4
    auto action = Sequence::create(
                                       MoveBy::create(2.0f, Point(150,0)),
                                       CallFuncN::create(std::bind(&ActionCallFuncN::callback,this,std::placeholders::_1)),
                                       NULL);
     
    1
    2
    3
    4
    5
    6
    7
    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表达式可以极大的简化回调代码,推荐使用。

  • 转自:http://www.2cto.com/kf/201401/275831.html

 

分享到:
评论

相关推荐

    Cocos2d-x 3.0开发-点击交互的四种处理.docx

    随着Cocos2d-x 3.0的发布,虽然这种方法仍然可用,但其实现方式发生了一些变化,例如使用了C++11的新特性来简化回调函数的绑定过程。下面通过示例代码来展示这一变化: ```cpp // 函数回调示例 void ...

    Cocos2d-x 3.x制作2048

    在《Cocos2d-x 3.x制作2048》这本书中,作者详细介绍了使用Cocos2d-x 3.0版本,通过C++语言开发2048游戏的全过程。2048是一款非常流行的数字拼接游戏,玩家需要通过滑动屏幕上下左右来移动数字卡片,相同数字的卡片...

    最新cocos2d-x 3.0博客教学 小游戏[史上最坑爹的游戏] 003第二关:点击绿色按钮100下

    Cocos2d-x 3.0版本引入了许多新特性和改进,包括性能优化、新的渲染系统、支持Lua脚本等。它提供了丰富的API和工具,使得游戏开发者能够轻松地创建2D游戏。 2. **游戏对象与场景**: 在Cocos2d-x中,游戏通常由多...

    结合cocos2d-js3.0结合cocos studio实现时钟倒计时功能

    Cocos2d-js是Cocos2d-x的一个分支,它允许开发者使用JavaScript编写游戏和应用,而Cocos Studio则是一个强大的可视化设计工具,用于创建游戏场景、UI布局和动画。 首先,我们需要了解Cocos2d-js的基础知识。它是一...

    Cocos2d-x 3.0开发(三)点击交互的四种处理beta2版代码

    本教程将深入探讨在Cocos2d-x 3.0 Beta2版本中处理点击交互的四种方法,帮助开发者更好地理解并实现游戏或应用的用户界面。 1. **触摸事件监听器(TouchListener)** Cocos2d-x 提供了`EventListenerTouchOneByOne`...

    Cocos2d-x3.0 四种点击交互处理Demo

    在Cocos2d-x 3.0中,更改了dispatch机制。同时加入了两种新的交互形式:listener 和touchEvent回调。加上先前版本中的点击函数回调,与重写layer层的touch消息响应,构成了一个相对完整的交互模式。本例运用四种方式...

    cocos2d-x 2.x action集合(详细注释分类)

    Cocos2d-x是一款开源的游戏开发框架,广泛用于2D游戏、交互式应用程序和教育软件的制作。2.x版本是其历史上的一个重要阶段,提供了丰富的功能和改进。在这个"cocos2d-x 2.x action集合(详细注释分类)"的资源中,你将...

    coco2d-x3.0 curl实现下载资源(支持断点续传)

    在cocos2d-x3.0游戏开发框架中,实现资源下载并支持断点续传是一...通过这些组件的协同工作,cocos2d-x3.0项目能够有效地实现curl库的资源下载并支持断点续传功能,为游戏提供高效、稳定且用户体验良好的资源加载服务。

    cocos2d-x-3.2文档

    在Cocos2d-x 3.2版本中,多点触摸功能被广泛应用于游戏和交互式应用中,允许用户同时处理多个触摸输入。这个功能的实现主要依赖于事件处理和事件分发机制的改进。以下是关于Cocos2d-x 3.2中多点触摸的详细说明: ...

    别踩白块游戏cocos2d-x3.x实现

    Cocos2d-x是一个广泛使用的开源游戏引擎,尤其适合2D游戏开发,它支持多种编程语言,包括C++、Lua和JavaScript。 首先,我们需要了解Cocos2d-x的基本架构。Cocos2d-x包含了一系列的类,如Scene(场景)、Layer(层...

    菜单 场景切换

    Cocos2d-x是一个广泛使用的开源2D游戏开发框架,支持多种编程语言,包括C++,并且兼容Cocos2dx 3.0版本。在这个主题中,我们将深入探讨如何在游戏或应用程序中实现菜单的动态切换,以及如何在不同的场景(Scene)...

    cocos2d打地鼠游戏demo

    这需要设置物理世界、定义物体的物理属性,并编写碰撞回调函数来响应碰撞事件。 5. **资源管理**:游戏中的图片、音频等资源需要被正确加载和管理。Cocos2D提供了纹理缓存和音频播放器等工具,确保资源的高效使用。...

    lua 绑定c++ 详细教程!

    // 实现菜单关闭回调函数 } ``` ##### 3. 使用Python脚本执行绑定 最后一步是通过Python脚本来执行绑定操作。在这个过程中,你需要复制`cocos2d-x-3.1.1/tools/tolua`目录下的`genbindings.py`文件,并对其进行...

    cocos2dx 3.0 加速计的使用(重力) 包含测试apk

    通过监听器的回调函数,可以获取到实时的`Acceleration`数据。 3. **实际应用示例** - **创建监听器**:首先,你需要创建一个实现了`ccAccelerateEventListener`接口的类,覆盖`onAccelerationUpdate`方法来处理...

    cocos-creator点击按钮切换界面,动态加载页面,按钮缩放

    首先,在按钮组件(`cc.Button`)上添加一个点击事件监听器,然后在监听器的回调函数中切换到目标场景。例如: ```javascript // 获取按钮节点 var button = cc.find('Canvas/Button'); // 添加点击事件监听...

    JS与C++间通讯DEMO

    在Cocos2d-x开发中,经常会遇到JavaScript与C++之间的交互需求,特别是在Cocos2d-html5这种混合开发环境中。Cocos2d-html5 v3.0 RC0引入了更强大的JavaScript绑定机制,使得JS与C++间的通信变得更加便捷。这个"JS与...

Global site tag (gtag.js) - Google Analytics