首页 > 代码库 > Cocos2d-x学习笔记(十)scheduler及Cocos2dx的回调

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)));
             
}

结言

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

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