Cocos2d-x 调度器 Scheduler
Coscos中的scheduler与节点有关,可以为每一个节点增加或删除scheduler,节点可以控制scheduler的开关。当节点不可见或者被一出时,节点上的scheduler也会停止。当cocos引擎暂停时,所有节点的scheduler也会暂停,cocos重新运行时scheduler也会重新运行。也可通过节点的成员函数Node::resume/ Node::pause暂停/恢复单个节点的Scheduler.
Cocos2d-x支持三种类型的Scheduler
每帧都调用的默认调度器Scheduler,schedulerUpdate(),调用节点的虚函数Update。
自定义调度器Scheduler,schedule(…),可以自定义调用函数,调用间隔,次数等等。
单次调度器scheduleOnce(…),可以自定义调用函数。
通过函数void Node::scheduleUpdate()打开
通过函数void Node::unscheduleUpdate()关闭
通过scheduleUpdate打开默认调度器后节点在每帧绘制前,都会调用下面虚函数
virtual void Node::update(floatf Delta)
所以如果节点要使用默认调度器,需要重写update函数。
可以通过以下节点Node类的成员函数设置自定义调度器
void schedule(SEL_SCHEDULE selector, float interval,unsigned int repeat,float delay);
void schedule(SEL_SCHEDULE selector, floatinterval);
void schedule(SEL_SCHEDULE selector);
void schedule(const std::function<void(float)>&callback,const std::string&key);
void schedule(const std::function<void(float)>&callback,float interval,const std::string &key);
void schedule(const std::function<void(float)>&callback,float interval,unsigned int repeat, float delay,const std::string &key);
自定义调度器支持两种形式的回调函数:
SEL_SCHEDULE为函数指针
const std::function<void(float)> &callback为C++11新特性Lambda表达式(匿名函数)
参数interval设为0,则代表每帧都调用
参数repeat设置为CC_REPEAT_FOREVER,则可以将调度器设为一直循环调用。
参数key,可以用于删除调度器,如果设置调度器时已经存在一共同名的key,则只会更新调度器的间隔时间,调度次数和回调函数不会更新。
可以通过以下节点Node类的成员函数删除自定义调度器
void unschedule(SEL_SCHEDULE selector);
void unschedule(const std::string &key);
void unschedule All Callbacks();
可以通过以下节点Node类的成员函数设置单次调度器
void scheduleOnce(SEL_SCHEDULE selector, float delay);
void scheduleOnce(conststd::function<void(float)> &callback,float delay,const std::string &key);
delay为设置后调用的时间。
单次调度器实际上就是特殊的自定义调度器,以下式Node节点中设置单次调度器的代码:
void Node::scheduleOnce(SEL_SCHEDULE selector,float delay)
{
this->schedule(selector, 0.0f,0, delay);//调用Node设置自定义调度器函数
}
void Node::scheduleOnce(const std::function<void(float)>&callback, float delay,const std::string &key)
{
//调用Node设置自定义调度器函数
_scheduler->schedule(callback, this,0, 0, delay, !_running,key);
}
所有节点的调度器都是由导演类Director中的变量Scheduler* Director:: _scheduler管理,scheduler在Director::init中被初始。在Director::drawScene函数中_scheduler->update(_deltaTime)会被调用。Scheduler::update(float dt)函数会处理每个节点设置的调度器。
在Scheduler类里面由三个成员变量
struct _listEntry*_updatesNegList; // listof priority < 0
struct _listEntry*_updates0List; // listpriority == 0
struct _listEntry*_updatesPosList; // listpriority > 0
当Node节点调用scheduleUpdateWithPriority(int priority)函数时,则会根据priority把节点的加入到相应的队列中,scheduleUpdate实际上是已priority = 0参数调用scheduleUpdateWithPriority。
在Scheduler::update(float dt)中依次遍历_updatesNegList、_updates0List、_updatesPosList链表,在遍历过程中会调用相应节点的update函数。
Scheduler类内部由一个Timer类的队列_hashForTimers,当Node类设置自定义调度器时,都会向Timer类里面添加一共Timer类型的对象。Timer类是一个接口类,实际添加的是TimerTargetSelector类或TimerTargetCallback类,这个两个类分别对应函数指针类型调度器和匿名函数(lambda表达式)类型的调度器。在Scheduler::update(float dt)中会遍历这个队列,并调用注册的函数。
他们之前的关系图如下: