事件回调

一:菜单事件的回调

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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // add a "close" icon to exit the progress. it's an autorelease object  
  2.     auto closeItem = MenuItemImage::create(  
  3.                                            "CloseNormal.png",  
  4.                                            "CloseSelected.png",  
  5.                                            CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));  

这个和2.X版本的回调函数有了不一样,原来是用menu_selector()的。我们查看CC_CALLBACK_1的定义可以看到以下代码。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // new callbacks based on C++11  
  2. #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)  
  3. #define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)  
  4. #define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)  
  5. #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的例子来进行改写,也就是

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CC_CALLBACK_1(HelloWorld::menuCloseCallback, this, 1 ,1));  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void HelloWorld::menuCloseCallback(Ref* pSender, int a, int b)  
  2. {  
  3.     //Director::getInstance()->end();  
  4.     int c = a+b;  
  5.     CCLog("this is a test");  
  6. }  

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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. auto closeItem = MenuItemImage::create(  
  2.                                            "CloseNormal.png",  
  3.                                            "CloseSelected.png",  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. std::bind(&HelloWorld::menuCloseCallback, this, std::placeholders::_1)  

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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. MenuItemImage * MenuItemImage::create(const std::string& normalImage, const std::string& selectedImage, const ccMenuCallback& callback)  
接着查询ccMenuCallback&可看到
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:SimSun;font-size:14px;">typedef std::function<void(Ref*)> ccMenuCallback;</span>  

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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. std::function<void(Ref*)> callback = std::bind(&HelloWorld::menuCloseCallback, this, std::placeholders::_1);  
  2.     auto closeItem = MenuItemImage::create(  
  3.                                            "CloseNormal.png",  
  4.                                            "CloseSelected.png",  
  5.                                            callback  
  6.     );  
接下来就要说一种比较有趣的方法,使用lambda表达式,先看代码

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. auto closeItem = MenuItemImage::create(  
  2.                                            "CloseNormal.png",  
  3.                                            "CloseSelected.png",  
  4.                                            [&](Ref*pSender){CCLog("this is a test"); }  
  5.     );  

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

这里假设我们定义了一个如上图的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的方式,如下面的例子:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:SimSun;font-size:14px;">    //testthe shedule  
  2.     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。下面我们用例子来说明使用。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //test the CallFunc  
  2.     //adda sprite with a normal piture  
  3.     autosprite = Sprite::create("CloseNormal.png");  
  4.     Size winSize = Director::getInstance()->getWinSize();  
  5.     sprite->setPosition(Point(winSize.width*0.5, winSize.height*0.1));  
  6.     this->addChild(sprite,0);  
  7.    
  8.     automove1 = MoveTo::create(1.5f, Point(winSize.width*0.9, winSize.height*0.5));  
  9.     automove2 = MoveTo::create(1.5f, Point(winSize.width*0.5, winSize.height*0.9));  
  10.     automove3 = MoveTo::create(1.5f, Point(winSize.width*0.1, winSize.height*0.5));  
  11.     automove4 = MoveTo::create(1.5f, Point(winSize.width*0.5, winSize.height*0.1));  
  12.    
  13.     //definethe CallFunc  
  14.     //CallFunc  
  15.     autoaction1 = CallFunc::create(CC_CALLBACK_0(HelloWorld::callback1, this));  
  16.     //CallFuncN  
  17.     autoaction2 = CallFuncN::create(CC_CALLBACK_1(HelloWorld::callback2, this));  
  18.     //CallFuncND  
  19.     autoaction3 = CallFuncN::create(CC_CALLBACK_1(HelloWorld::callback3, this , 1));  
  20.     //CallFuncO  
  21.     auto action4 = CallFunc::create(CC_CALLBACK_0(HelloWorld::callback4, this, sprite));  
  22.   
  23.     auto seq = Sequence::create(move1, action1, move2, action2, move3, action3, move4, action4, NULL);  


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void HelloWorld::callback1()  
  2. {  
  3.    CCLog("the callback test begin");  
  4. }  
  5. void HelloWorld::callback2(Node* node)  
  6. {  
  7.     CCLog("the sprite's position is x=%f, y=%f", node->getPositionX(),node->getPositionY());  
  8. }  
  9. void HelloWorld::callback3(Node* node, inta)  
  10. {  
  11.    CCLog("the sprite's position is x=%f, y=%f", node->getPositionX(),node->getPositionY());  
  12.    CCLog("%d",a);  
  13. }  
  14. void HelloWorld::callback4(Ref* ref)  
  15. {  
  16.    autosprite = static_cast<Sprite*>(ref);  
  17.    CCLog("the sprite's position is x=%f, y=%f",sprite->getPositionX(), sprite->getPositionY());  
  18. }  

最后看看输出,测试成功


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

 

      auto move = MoveTo::create(0.05, Point(Point(visible.width/2 + origin.x - mfWidth*mpUpComputerSelectArr.size()/2, visible.height/2 - 100)));              

      auto time = DelayTime::create(0.05);

       auto sequence = Sequence::create(move, time, CallFuncN::create(CC_CALLBACK_1(GameScene::setAnimationOfOutPoker, this, 1)),  NULL);

       sp->runAction(sequence);

       void GameScene::setAnimationOfOutPoker(Ref* r, int player){

        }

       

      


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值