原创文章,转载请注明出处: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))); }
结言
剩下三种回调我们将在接下来的学习笔记中继续讲到,有了目前学的回调,是不是觉得已经可以做一个简单的飞机大战了呢?