cocos2d-x 3.0 回调事件

时间:2023-02-09 00:11:44

    cocos2d-x3.0 中使用了C++11的性特性,因此回调的方式也相应地做了一些改变,因此我们需要先去了解一下C++11中的std::function,std::bind和lambda表达式,可以参考下面这篇博客http://www.cnblogs.com/nzbbody/p/3489573.html,在此还是感谢那些不辞劳苦分享经验的朋友。

一:菜单事件的回调

回到主题,我们先创建一个HelloWorld的工程并打开源代码,可以看到

// add a "close" icon to exit the progress. it's an autorelease object
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

这个和2.X版本的回调函数有了不一样,原来是用menu_selector()的。我们查看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_CALLBACK_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__)

    这是宏定义std::bind的方式,其中##__VA_ARGS__表示的是可变参数列表,也就是后面还是可以定义任意个参数的,而std::placeholders则是为不预先绑定的参数预留传参的位置,这里的0,1,2,3就是表示回调函数中不事先绑定的参数的个数。


下面我们可以对Helloworld的例子来进行改写,也就是

CC_CALLBACK_1(HelloWorld::menuCloseCallback, this, 1 ,1));
void HelloWorld::menuCloseCallback(Ref* pSender, int a, int b)
{
    //Director::getInstance()->end();
	int c = a+b;
	CCLog("this is a test");
}

因为CC_CALLBACK_X是std::bind的宏定义,所以也可以直接使用如下所示:

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

通过查看MenuItemImage::create可以看到

MenuItemImage * MenuItemImage::create(const std::string& normalImage, const std::string& selectedImage, const ccMenuCallback& callback)
接着查询ccMenuCallback&可看到
<span style="font-family:SimSun;font-size:14px;">typedef std::function<void(Ref*)> ccMenuCallback;</span>

也就是如果你喜欢,也可以使用std::function的形式来使用回调函数,如下:

std::function<void(Ref*)> callback = std::bind(&HelloWorld::menuCloseCallback, this, std::placeholders::_1);
    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
										   callback
	);
接下来就要说一种比较有趣的方法,使用lambda表达式,先看代码

auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           [&](Ref*pSender){CCLog("this is a test"); }
    );

    使用这种方式有什么好处呢?我觉得这样调用的话函数是匿名的,可以防止别人的访问,同时不用我们再去创建函数,对于函数体较少的函数而言,这样的确省去一些功夫。下面我们简单说说lambda表达式的语法:

cocos2d-x 3.0 回调事件

这里假设我们定义了一个如上图的lambda表达式。现在来介绍途中标有编号的各个部分是什么意思。

1.  Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示一引用的方式;‘=’表明以值传递的方式捕获,除非专门指出。

2.  Lambda表达式的参数列表

3.  Mutable 标识

4.  异常标识

5.  返回值

6. “函数”体,也就是lambda表达式需要进行的实际操作

二:定时器事件的回调

这个貌似和之前2.x的版本一样,分3种定时器:

1.   默认调度器:schedulerUpdate()

添加启动定时器代码this->scheduleUpdate();然后重载update(float dt)即可

2. 自定义调度器:schedule(SEL_SCHEDULE selector, float interval, unsignedintrepeat, float delay),其中1. 第一个参数selector即为你要添加的事件函数2. 第二个参数interval为事件触发时间间隔3. 第三个参数repeat为触发一次事件后还会触发的次数,默认值为kRepeatForever,表示无限触发次数4. 第四个参数delay表示第一次触发之前的延时

其中回调的方式还是使schedule_selector的方式,如下面的例子:

<span style="font-family:SimSun;font-size:14px;">    //testthe shedule
    this->schedule(schedule_selector(HelloWorld::testSchedule),2.0f);</span>

不过要注意的是testSchedule要带一个float的参数,否则不起效果。

3. 单次调度器:scheduleOnce(SEL_SCHEDULE selector, float delay)

这个使用同上,只不过只执行一次而已。

三:动作回调函数

    当一个node执行完成了某个动作后,我们可能需要它响应一些其他的事件,这时候我们就用到回调函数这个功能。2.x的版本里,这种类型的函数有4种形式可供我们选择使用,分别为:

1)  CCCallFunc:无参回调函数

2)  CCCallFuncN:带一个CCNode*参数回调函数,“N”表示CCNode

3)  CCCallFuncND:带一个CCNode*和一个void*参数的回调函数,“N”表示CCNode"D"表示Data

4)  CCCallFunO:带一个CCObject*参数的回调函数,"O"表示CCObject 

    使用的方式也是callfunc_selector, callfuncX_selector这样的形式,但是到3.0之后,只保留了CallFuncCallFuncN两个动作,用来在动作中进行方法的调用。不过我们还是可以利用CallFuncCallFuncN来等价实现CallFuncNDCallFuncO。下面我们用例子来说明使用。

//test the CallFunc
    //adda sprite with a normal piture
    autosprite = Sprite::create("CloseNormal.png");
    Size winSize = Director::getInstance()->getWinSize();
    sprite->setPosition(Point(winSize.width*0.5, winSize.height*0.1));
    this->addChild(sprite,0);
 
    automove1 = MoveTo::create(1.5f, Point(winSize.width*0.9, winSize.height*0.5));
    automove2 = MoveTo::create(1.5f, Point(winSize.width*0.5, winSize.height*0.9));
    automove3 = MoveTo::create(1.5f, Point(winSize.width*0.1, winSize.height*0.5));
    automove4 = MoveTo::create(1.5f, Point(winSize.width*0.5, winSize.height*0.1));
 
    //definethe CallFunc
    //CallFunc
    autoaction1 = CallFunc::create(CC_CALLBACK_0(HelloWorld::callback1, this));
    //CallFuncN
    autoaction2 = CallFuncN::create(CC_CALLBACK_1(HelloWorld::callback2, this));
    //CallFuncND
    autoaction3 = CallFuncN::create(CC_CALLBACK_1(HelloWorld::callback3, this , 1));
    //CallFuncO
    auto action4 = CallFunc::create(CC_CALLBACK_0(HelloWorld::callback4, this, sprite));

    auto seq = Sequence::create(move1, action1, move2, action2, move3, action3, move4, action4, NULL);
<span style="font-size: 12px;">    </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">sprite->runAction(seq);</span>


void HelloWorld::callback1()
{
   CCLog("the callback test begin");
}
void HelloWorld::callback2(Node* node)
{
    CCLog("the sprite's position is x=%f, y=%f", node->getPositionX(),node->getPositionY());
}
void HelloWorld::callback3(Node* node, inta)
{
   CCLog("the sprite's position is x=%f, y=%f", node->getPositionX(),node->getPositionY());
   CCLog("%d",a);
}
void HelloWorld::callback4(Ref* ref)
{
   autosprite = static_cast<Sprite*>(ref);
   CCLog("the sprite's position is x=%f, y=%f",sprite->getPositionX(), sprite->getPositionY());
}

最后看看输出,测试成功

cocos2d-x 3.0 回调事件

同理,也可以像上面所提到的利用std::bind,std::function和lambda表达式来实现也可以。推荐还是lambda吧。

 

四:触摸回调函数

       这个准备在总结触摸机制的时候再慢慢讨论拉。


文章就写到这里了,如果有理解不妥的地方,还请各位朋友提出指正,谢谢!!