cocos2dx系列之回调函数


 >>> 原文链接: http://www.mayflygeek.com/archives/90/  

 >>> 转载自蜉蝣极客《cocos2dx系列之回调函数》 

大部分的cocos2dx开发者可能会多多少少的遇到一些cocos2dx的回调问题,
在这里呢,我想具体的来说下cocos2dx中的回调到底是怎么回事,那么我就以我们常用的
回调接口callfuncO_selector来说一说,首先,我觉得再说之前有必要先把C/C++中的函数指针
来说一下。

大家都会发现,int型也好,double型也好,还是bool型,对此的教程并不多,因为大家都知道如何去用,我要定义一个变量,我就可以int numfloat num,我要定义函数就可以int fun(),或者float fun(),再或者 void fun()。但是有一种类型确至始至终一直在困扰这很多的初学者,就是(类型 *)这个类型,其实,他是语言给我们提供访问底层内存的接口,有了这个,你就可以去访问底层的内存,或者说计算机硬件的寄存器,而它就是指针,那么对于(类型*)的用法有很多,大致归结如下:

1) 定义变量
int *point = &num
而其中的point就是指针变量,准确说是int型的指针变量,诸如此类的定义如下,float *fl
char* buf;等等,那么以point为例,point其实就是咱们静态的分配的一块内存区域,如果不进行初始
化,那么定义完之后就是int* point 这个point就是一个野指针,野指针容易造成内存泄漏等等内存问题,
可能会带来不必要的麻烦,所以在使用时最好还是将它初始化,如果没有什么特别的需求就将他int * = NULL;就可以了。
2) 定义函数(函数返回值类型)
比如 int* fun();那么这个就是一个返回int* 类型的函数,所以这种情况下,在函数的实现中
要有:

int * fun()
{
    int *num;
    。。。//函数体
    
    return num;
}

至于更深的问题在这里就不追究了,因为不是本文的重点
3) 作为函数参数
比如 int* fun(int *num),而实现中,我们就应该如下所示:
int \* fun(num)//num是一(int*)类型的一个实参

{
    int \*vlaue = num;
    ....//函数体
    return  value;
}

有的人会对这段代码感兴趣,int *vlaue = num;其实这里的实现就是一段拷贝过程,vlaue拿到的地址还
是num的地址。具体的不多说了。
4) 定义数组指针
比如 int (*arr)[5];这里所定义的就是一个数组指针,它的意思不是说数组里面的元素都是指针(
那是指针数组),而是说这个指针指向的是一个数组,然而,我们访问第一位时,其实就是数组名,就代表这第一个元素,可以**arr这么写就行了。在这里笔者不多写了,数组指针也就是和二维数组常在一起使用,我再次贴上一段代码:

#include <stdio.h>

int main()
{
    int a[3][5] = {
    {0,1,2,4,5},{6,7,8,9,10},{11,12,13,14,15}
    };
    int (*arr)[5];
    arr = a;
    printf("%d",*(*arr + 4));
}

大家可以编译试一试。

5) 定义指针数组
指针数组顾名思义就是一个数组里的元素都是指针,定义为int *arr[4];意思为含有四个指针变量的数组,
每个元素都是一个指针,都可以来存储一些地址,大家可以用for循环讲一个数组里的每个元素的地址全部给指针数组的元素便可以知道指针数组咋回事了。

6) 函数指针
在上面的int* fun()函数,我们可以将他称之为指针函数,而现在讲的是函数指针,这个特别容易混淆
。函数指针一直是C/C++的精华部分,有了它就可以封装各种回调。先来说下函数指针,首先定义一个函数指针比如 :int (*)fun(参数);其实辨别一个函数是函数指针还是指针只要看“ * ”是在括号里面还是括号外面。外面的就是指针函数,里面的就是函数指针。而我们怎样对
这个函数指针赋值呢? 比如我定义一个函数 int max();我们知道函数名就是函数的地址,所以,
fun = max;可见fun也就是存放的函数的地址。那么有了函数的地址,什么都好办了。而我们要执行这个max函数
就可以直接*max或者直接max就可以了。
接下来我们就可以看看cocos2dx中的实现了。首先来到callfuncO_selector,我们可以看到他的定义

#define callfuncO_selector(_SELECTOR) CC_CALLFUNCO_SELECTOR(_SELECTOR)

看来cocos中是用的
宏来作为相关的定义,而它的实现就是CC_CALLFUNCO_SELECTOR(_SELECTOR),所以,我们就看看这个
CC_CALLFUNCO_SELECTOR(_SELECTOR)的实现,如下:

#define CC_CALLFUNCO_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR)

看来又要看看static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR),static_cast关键字是类型转换,
它意思是将传进来的参数&_SELECTOR强制转化为cocos2d::SEL_CallFuncO类型,(通常这个&_SELECTOR
就是咱们好写的“类名::函数名”,比如通常“helloword::menucallback”这种写法),而cocos2d::SEL_CallFuncO又是什么呢?我们再看它实现:

typedef void (Ref::*SEL_CallFuncO)(Ref*);

它是什么呢?就是一个函数指针啊,函数名Ref::*SEL_CallFuncO,他用了关键字typedef,是类型化了这个
Ref::*SEL_CallFuncO,比如我们写typedef int(*fun)();我们就是通过typedef将fun定义为了一个类型,就可以
fun max定义变量了;max就是一个指向函数的指针。所以这个Ref::*SEL_CallFuncO就是一个类型了,我们
就可以进行强制转换了。当转换为cocos常用一些类型接口后就可以进行操作了,我觉个定时器的例子,一看便知,以下就是cocos源码实现:

void Node::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)
{
    CCASSERT( selector, "Argument must be non-nil");
    CCASSERT( interval >=0, "Argument must be positive");

    _scheduler->schedule(selector, this, interval , repeat, delay, !_running);
}

selector就是被强转为SEL_SCHEDULE类型后的形参,比如我们写:

this->schedule(SEL_SCHEDULE(&palygame::move),0.02f);

就是将move强转为SEL_SCHEDULE类型,然后 他们再通过:

 _scheduler->schedule(selector, this, interval , repeat, delay, !_running);

进行实现,这里的selector就是“&palygame::move”也就是函数move的地址。之后引擎会对这个地址进行保存,然后改用的时候就会直接在地址前加个“*”就可以回调回来了。
好了,回调就说到这,纯手打,望见谅,写的不好忘见谅。下一期回调“CC_CALLBACK_0”,也就是C++中常用的模版的使用,希望大家继续支持哦!


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值