Cocos2d-x学习笔记(十)scheduler及Cocos2dx的回调

原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38893795

前言

看完了前九节的学习笔记,我们已经基本上可以做一些简单的界面了,但是如果我们想要让东西不断动起来怎么办呢?答案很简单,用scheduler,我们先来看看schedule的用法吧。

scheduler用法

在之前CCNode的学习中,我们介绍了部分schedule的方法,现在我们来回顾一下:

// 返回指定计划是否正在执行
bool isScheduled(SEL_SCHEDULE selector);

// 设置帧更新计划,每帧都调用update方法,相当于schedule了update方法,实际调用了scheduleUpdateWithPriority,设置优先级为0
void scheduleUpdate(void);

// 取消帧更新计划
void unscheduleUpdate(void);

// 设置帧更新计划,每帧都调用update方法,相当于schedule了update方法,在CCSchedule更新update时,会根据schedule的优先级排序调用
void scheduleUpdateWithPriority(int priority);

/**
 * 执行某个计划
 *
 * @param interval  触发间隔时间(单位:秒),0为每帧都触发,如果interval = 0,推荐使用scheduleUpdate()代替
 * @param repeat    重复次数(实际执行次数为:重复次数+1)
 * @param delay     延迟启动时间(单位:秒)
 * @lua NA
 */
void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
void schedule(SEL_SCHEDULE selector, float interval);
void schedule(SEL_SCHEDULE selector);

// 执行指定计划一次
void scheduleOnce(SEL_SCHEDULE selector, float delay);

// 取消指定计划
void unschedule(SEL_SCHEDULE selector);

// 取消所有计划
void unscheduleAllSelectors(void);

// 恢复/暂停节点的计划和动作
void resumeSchedulerAndActions(void);
void pauseSchedulerAndActions(void);

void CCNode::scheduleUpdate()
{
    scheduleUpdateWithPriority(0);
}

void CCNode::scheduleUpdateWithPriority(int priority)
{
    // 调用CCSchedule启动指定节点的帧更新,并设置优先级
    m_pScheduler->scheduleUpdateForTarget(this, priority, !m_bRunning);
}

void CCNode::unscheduleUpdate()
{
    // 调用CCSchedule的取消指定节点的指定计划
    m_pScheduler->unscheduleUpdateForTarget(this);
    if (m_nUpdateScriptHandler)
    {
        CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptHandler(m_nUpdateScriptHandler);
        m_nUpdateScriptHandler = 0;
    }
}

void CCNode::scheduleOnce(SEL_SCHEDULE selector, float delay)
{
    // 调用schedule,将间隔时间设置为0秒,将重复次数设置为0此,即只执行一次
    this->schedule(selector, 0.0f, 0, delay);
}

void CCNode::schedule(SEL_SCHEDULE selector)
{
    // 调用schedule,将间隔时间和延迟启动时间设置为0秒
    this->schedule(selector, 0.0f, kCCRepeatForever, 0.0f);
}

void CCNode::schedule(SEL_SCHEDULE selector, float interval)
{
    // 调用schedule,将重复次数设置为永远,延迟启动时间为0秒 #define kCCRepeatForever (UINT_MAX -1)
    this->schedule(selector, interval, kCCRepeatForever, 0.0f);
}

void CCNode::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)
{
<pre name="code" class="cpp">    // 确保待执行计划不为空,两次计划执行时间间隔大于0

CCAssert( selector, "Argument must be non-nil");

CCAssert( interval >=0, "Argument must be positive");

// 调用CCSchedule的启用指定节点的指定计划

m_pScheduler->scheduleSelector(selector, this, interval , repeat, delay, !m_bRunning);

}

void CCNode::unschedule(SEL_SCHEDULE selector)

{

// 确保待取消计划不为空

if (selector == 0)

return;

// 调用CCSchedule的取消指定节点的指定计划

m_pScheduler->unscheduleSelector(selector, this);

}

void CCNode::unscheduleAllSelectors()

{

// 调用CCSchedule的取消指定节点所有计划

m_pScheduler->unscheduleAllForTarget(this);

}

void CCNode::resumeSchedulerAndActions()

{

// 调用CCSchedule和CCActionManager的暂停

m_pScheduler->resumeTarget(this);

m_pActionManager->resumeTarget(this);

}

void CCNode::pauseSchedulerAndActions()

{

// 调用CCSchedule和CCActionManager的恢复

m_pScheduler->pauseTarget(this);

m_pActionManager->pauseTarget(this);

}


看到这,我们做一个简单的计划任务吧,假设我们当前在做飞机大战,现在需要每0.5s添加一辆飞机:

schedule(schedule_selector(GameScene::addEnemy), 0.5f);

Cocos2dx的回调

在代码中我们看到了许多诸如SEL_SCHEDULE的变量,在最后实现一个定时任务的时候也看到了schedule_selector,它们究竟是什么?其实它就是实现回调的核心,我们一起看看他们的真面目吧:

typedef void (CCObject::*SEL_SCHEDULE)(float);
typedef void (CCObject::*SEL_CallFunc)();
typedef void (CCObject::*SEL_CallFuncN)(CCNode*);
typedef void (CCObject::*SEL_CallFuncND)(CCNode*, void*);
typedef void (CCObject::*SEL_CallFuncO)(CCObject*);
typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
typedef void (CCObject::*SEL_EventHandler)(CCEvent*);
typedef int (CCObject::*SEL_Compare)(CCObject*);

#define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR) // schedule计划回调
#define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR) // 动作回调
#define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR)
#define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR)
#define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR)
#define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) // 菜单回调
#define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) // 事件回调
#define compare_selector(_SELECTOR) (SEL_Compare)(&_SELECTOR) // 

简单分析一下define和typedef:

#define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR)

#define: 只是一个加单的字符串替代宏,#define A B 的意思是:A和B是一样的东西,只不过换了个写法,经常用在:用一个简单的字符串代替一串复杂的字符串、用一些有意义的单词组合来代表某些值。

typedef void (CCObject::*SEL_SCHEDULE)(float);

typedef: 定义一种类型的别名, typedef void (*fff)(float) 表示fff是一个函数,这个函数的返回类型是 void ,只有一个 float 类型的参数。

CCCallFunC家族

在这里,我们已经学会了schedule_selector的用法,接下来我们看看callfunc_selector家族的用法吧,它们主要在我们需要在一个动作完成之后需要调用某个函数时使用:

class HelloWorld : public cocos2d::CCLayerColor
{
public:
    virtual bool init();
    static cocos2d::CCScene* scene();

    void callBack();
    void callNodeBack(CCNode* sender);
    void callNodeBack(cocos2d::CCNode *sender, void * data);
    void callObjectBack( CCObject * data);
    CREATE_FUNC(HelloWorld);
};
void HelloWord::init{
    ...
    CCSprite* player = CCSprite::create("Icon.png");
    player->setPosition(ccp(100, 100));
    this->addChild(player);
    CCMoveTo* action = CCMoveTo::create(1, ccp(200, 200));

    // CCCallFunc的功能非常简单,它只能简单地实现在动作序列中帮助我们调用一个函数的功能。
    CCCallFunc* call  = CCCallFunc::create(this, callfunc_selector(HelloWorld::callBack));
    // 下面这行代码是创建一个动作序列
    CCFiniteTimeAction* seq = CCSequence::create(action,call,NULL);
    player->runAction(seq);

    // CCCallFuncN的回调,既能够调用一个方法还能够将调用的对象传过去  这里的调用对象就是player  它是个精灵对象
    CCCallFuncN* callN = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::callNodeBack));
    CCFiniteTimeAction* seq2 = CCSequence::create(action,callN,NULL);
    player->runAction(seq2);

    // CCCallFuncND的回调,先创建一个字典
    CCDictionary* dic = CCDictionary::create();
    dic->retain();
    dic->setObject(CCString::create("zxcc"), 1);
    // CCCallFuncND可以传递一个任意数据类型,例如,我们此时传递一个字典
    CCCallFuncND* callND = CCCallFuncND::create(this, callfuncND_selector(HelloWorld::callNodeBack),(void*)dic);
    CCFiniteTimeAction* seq3 = CCSequence::create(action,callND,NULL);
    player->runAction(seq3);

    // CCCallFuncO的回调,我们创建一个精灵
    CCSprite* player2 = CCSprite::create("player2.png");
    player2->setPosition(ccp(300, 300));
    this->addChild(player2);
    // CCCallFuncO传值的类型只能为CCObject类型,例子为先移动一个精灵,再移动另一个精灵
    CCCallFuncO* callO = CCCallFuncO::create(this, callfuncO_selector(HelloWorld::callObjectBack), player2);
    CCFiniteTimeAction* seq4 = CCSequence::create(action,callO,NULL);
    player->runAction(seq4);
}

//CCCallFunc的回调函数
void HelloWorld::callBack()
{
    CCLog("CCCallFunc");
}

//CCCallFuncN的回调函数
void HelloWorld::callNodeBack(cocos2d::CCNode *sender)
{
    CCSprite* player = (CCSprite*) sender;
    CCLog("%f",player->getPosition().x);
}

//CCCallFuncND的回调函数
void HelloWorld::callNodeBack(cocos2d::CCNode *sender, void * data)
{
    CCDictionary* dic = (CCDictionary*)data;
    CCString* str = (CCString*)(dic->objectForKey(1));
    CCLog("%s",str->getCString());
}

//CCCallFuncO的回调函数
void HelloWorld::callObjectBack(cocos2d::CCObject *data)
{
    CCSprite* player = (CCSprite*)data;
    player->runAction(CCMoveTo::create(1, ccp(1 ,90)));

}

结言

剩下三种回调我们将在接下来的学习笔记中继续讲到,有了目前学的回调,是不是觉得已经可以做一个简单的飞机大战了呢?

时间: 2024-10-15 22:10:02

Cocos2d-x学习笔记(十)scheduler及Cocos2dx的回调的相关文章

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

第十七篇:实例分析(3)--初探WDDM驱动学习笔记(十)

续: 还是记录一下, BltFuncs.cpp中的函数作用: CONVERT_32BPP_TO_16BPP 是将32bit的pixel转换成16bit的形式. 输入是DWORD 32位中, BYTE 0,1,2分别是RGB分量, 而BYTE3则是不用的 为了不减少color的范围, 所以,都是取RGB8,8,8的高RGB5, 6, 5位, 然后将这16位构成一个pixel. CONVERT_16BPP_TO_32BPP是将16bit的pixel转换成32bit的形式 输入是WORD 16BIT中

初探swift语言的学习笔记十(block)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35783341 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在前面一些学习中,原本把闭包给理解成了block尽管有很多相似之处,但block还是有他自己的独特之外.近日,在写oc/swift混合编码时,有时候需要swift回调oc,oc回调swift . 因此我把swift中的 block 常见的声明和写

Swift学习笔记十:属性

1.存储属性       1. 作为特定类或结构实例的一部分,存储属性存储着常量或者变量的值.存储属性可分为变量存储属性(关键字var描述)和常量存储属性(关键字let描述). struct student{ let name = "" var score = 0 } let a = student(name:"小笨狼",score:96)           注意:                ① 定义储存属性时,需要为每一个属性定义一个默认值.在初始化的时候,

python学习笔记十——异常处理

1.try: command except 错误类型,记录错误信息变量: command finally: command try...finally的用处是无论是否发生异常都要确保资源释放代码的执行.一般来说,如果没有发生错误,执行过try语句块之后执行finally语句块,完成整个流程.如果try语句块发生了异常,抛出了这个异常,此时就马上进入finally语句块进行资源释放处理.如下从几个细节讨论finally的特性. 1).try中的return: 当在try语句块中含有return语句

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

Linux System Programming 学习笔记(十) 信号

1. 信号是软中断,提供处理异步事件的机制 异步事件可以是来源于系统外部(例如用户输入Ctrl-C)也可以来源于系统内(例如除0) 内核使用以下三种方法之一来处理信号: (1) 忽略该信号.SIGKILL和SIGSTOP不能被忽略. (2) 捕捉并且处理该信号.The kernel will suspend execution of the process's current code path and jump to a previously registered function. SIGK

APUE 学习笔记(十) 高级I/O

1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套接字 2. 管道 管道进行IPC有两个局限: (1) 半双工,即数据只能在一个方向上流动 (2) 只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道 fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISF

angular学习笔记(十九)

本篇主要介绍angular使用指令修改DOM: 使用angular指令可以自己扩展html语法,还可以做很多自定义的事情.在后面会专门讲解这一块的知识,这一篇只是起到了解入门的作用. 与控制器,过滤器,服务,一样,可以通过模块实例的directive的方法来创建指令: var someModule = angular.module('SomeModule',[]); someModule.directive('directiveName',function(){ return { link: f

Swift学习笔记十四:构造(Initialization)

类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值.存储型属性的值不能处于一个未知的状态. 你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值.以下章节将详细介绍这两种方法. 注意: 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(property observers). 一.基本语法 class Human{ var name :String init(){ name = "human" } init(n