浅析回调函数和Schedule

Cocos2d-x中涉及到不少的回调函数,有时候我们在用的过程中并没有留意,但如果你仔细推敲一下,发现这里边的故事还真不少,本文借助菜单回调和schedule回调来说下3.0中的回调函数的一些应用。


1、回调的第一种方法,传统方法,传入target和回调函数,在适当的时候用target调用回调函数。

以下的函数调用是2.x创建菜单项使用回调函数的方法,第三个参数是target,第四个参数需要传入一个函数指针,这个函数指针的定义是:typedef void (Ref::*SEL_MenuHandler)(Ref*);传入的第三第四个参数的作用就是当需要回调函数的时候用target来调用你传入的这个函数,所以这个函数一定是target的成员变量。

1
automenu1=MenuItemImage::create( "CloseNormal.png" , "CloseSelected.png" this 2、回调的第二种方法,使用std::bind

CC_CALLBACK_1的定义std::bind(&__selector__,__target__,std::placeholders::_1,##__VA_ARGS__) bind其实就是传入一个函数,产生一个新的函数,第一个就是一个函数地址,如果这个函数是类的成员函数,我们需要第二个参数,告诉调用哪个对象的这个函数,第三个参数是一个占位符,CC_CALLBACK_0,CC_CALLBACK_1 ...的不同点就在这里,后边的数字代表的就是bind的占位符数量,引擎对他们进行了不同的宏定义,可以跟进查看,后边的##__VA_ARGS__可以传入多个参数

automenu2=MenuItemImage::create());

下面不使用Cocos2d-x的callback宏,我们来直接使用bind

1
automenu3=MenuItemImage::create( false 这里是callback的定义void HelloWorld::callback(cocos2d::Ref * ref,int i,bool b),我们使用bind绑定了这个函数,将它的第一个参数使用占位符保留了下来,而第二个和第三个参数分别提供了值,这个时候通过bind就产生了一个新的函数callback(cocos2d::Ref * ref)。系统在回调的时候会传入一个ref的参数,而i和b就是我们在bind中提供的值。

最后我们来看一下menu3的create的第三个参数ccMenuCallback,它的定义如下:typedef std::function<void(Ref*)> ccMenuCallback;这个东西就是std::function,尖括号中的内容就是告诉你它需要的函数返回值是void,而需要的参数是Ref *,也就是说它需要的是返回值是void,参数是Ref *的函数,所以std::function其实就是一种类型,就像普通的数据类型那样的类型,一种用来说明函数类型的类型,最后的最后我们知道通过std::bind绑定的函数需要使用std::function类型去接受。

3、回调的第三种方法:使用lambda表达式

将lambda表达式直接写在参数中:

1
2
3
4
automenu4=MenuItemImage::create( [](Ref*ref){
log ( "close" );
});

如果要使表达式能够访问外部变量,可以在[]内写入“&”或者“=”加上变量名,其中“&”表示按引用访问,“=”表示按值访问,变量之间用逗号分隔。

4
5
6
autocloseMenu1=MenuItemImage::create( [ autosprite=Sprite::create( "HelloWorld.png" );
sprite->setAnchorPoint(Point(0,0));
->addChild(sprite);
为了说明lambda的类型,这次将lambda写到参数列表的外边。

3
std::function< void (Ref*)>call=[](Ref*ref)
{};
autocloseMenu2=MenuItemImage::create( "" 更多的时候为了省事,我们都将std::function的那一长串东西用一个auto代替。通过上面的例子就说明了lambda返回的类型也是需要std::function接收的,通过上面的例子我们得出这样的结论,如果要回调某一个函数,就像菜单的回调,按钮的回调,schedule的回调,CCallFunc动作序列,我们可以传入函数指针+调用对象target,或者使用std::function,而std::function可以通过std::bind绑定获得,或者通过lambda表达式获得。

接下来看一下回调函数在schedule中是如何应用的。

2
->schedule(SEL_SCHEDULE(&HelloWorld::call),1.0f);
->schedule(schedule_selector(HelloWorld::call),1.0f);

以下的两种调用方式道理都是一样的,仔细比较一下发现使用SEL_SCHEDULE需要加一个取地址符,使用schedule_selector不需要,原因看下各自的定义大家就明白了。SEL_SCHEDULE直接就是函数指针,而schedule_selector是个宏定义,传入里边的参数,用static_cast转化为SEL_SCHEDULE类型的时候加上了取地址符。这里把这个基础的问题说下,也是对C++的一种复习吧!

2
typedef (Ref::*SEL_SCHEDULE)( float );
#defineschedule_selector(_SELECTOR)static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)

我们发现一个问题,用这种方法做回调的时候,不是需要传入一个target吗,为什么这种方法没有传入这个target,或者说是this参数,我们只好翻翻源码了,那就一步步跟进源码,跟到这里(代码在下边)的时候发现了用变量_schedule调用了一个schedule函数,这个_schedule是什么,我们在文件中查找一下,发现_scheduler = director->getScheduler();原来它是通过Director获得的,其实它的类型是Scheduler,这个东西是一个单例,在Director类中保持着对这个单利对象的引用。同时这个schedule函数的第二个参数就是this,而这个this就是我们要得target,所以这就说明这个target不是没有传入,而是在引擎的内部传入了this!

6
7
Node::schedule(SEL_SCHEDULEselector, interval,unsigned int repeat,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">delay)
{
CCASSERT(selector,monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"Argumentmustbenon-nil" CCASSERT(interval>=0,monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"Argumentmustbepositive" );
_scheduler->schedule(selector,interval,repeat,delay,!_running);
}

我们继续跟进schedule函数,发现文件跳到了Scheduler类中,调用了Scheduler类的schedule,到这里所有的东西就明白了。我们在类中调用schedule,表面上调用的是Node类的schedule,其实最后调用的是Scheduler类中得schedule函数。我们所说的第一种形式的回调this的传入是在node类中转调用scheduler中的schedule的时候帮我们传入了this。最后有必要看一下这个schedule的声明。

Scheduler::schedule(SEL_SCHEDULEselector,Ref*target,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">delay,monospace!important; font-size:1em!important; min-height:auto!important; color:gray!important; background:none!important">boolpaused)

那我们想要的第二种回调的形式呢?我找了Node的整个schedule函数都没有发现,因为Node最终还是调用的scheduler类的函数,所以我们去scheduler类中找一找,果然,我发现了采用第二种回调形式的schedule函数,声明如下。

1
Scheduler::schedule( const ccSchedulerFunc&callback,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">*target,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">paused,monospace!important; font-size:1em!important; min-height:auto!important; background:none!important">std::string&key)

我们跟进去看一下ccSchedulerFunc的定义,如下:

1
typedef ( )>ccSchedulerFunc;

怎么样,一个std::function出来了吧,但是Node中却没有提供给我们这样的schedule函数调用,有如此简单的调用形式却不用岂不是可惜?那我们要怎么办?很简单,直接使用Scheduler中得函数不就可以了。所以采用第二种回调方式的调用方法如下。

2
auto_schedule=Director::getInstance()->getScheduler();
_schedule->schedule([]( float tm ){ "%f" );},1.0f,! ->isRunning(),monospace!important; font-size:1em!important; min-height:auto!important; color:blue!important; background:none!important">"xiaota" );

现在,我们可以尽情的使用lambda表达式了,省去了麻烦的函数头文件声明,这几个参数很简单是类似于普通的schedule函数,只是最后一个参数要注意一下,他是一个string类型,这个string类型有什么作用呢?我们让schedule跑了起来,停的时候该怎么办呢?对,就是用的这个string,当然还有第二个参数target,所以这里你传入的这个key值必须和其他的key值保持不同,否则的话停掉的时候就出错了。这个原因估计也是引擎组没有将这个接口放到Node中得因素吧!现在schedule的用法和小小的分析就到这里结束了,大家如果发现有什么错误之处还请指正!

来源网址:http://www.cocoachina.com/bbs/read.php?tid=217556

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是