cocos提供了灵活的机制来实现游戏对象的状态更新,我们可以向scheduler注册回调函数来实现更新逻辑,scheduler提供了两种回调更新机制:
一、schedule
schedule:自定义间隔
注册自定义回调,需要用到Timer对象进行计时,需要花费更多内存和计算,且不能指定优先级,谨慎使用。
// callback: 重复执行的函数,如果callback已经被schedule,则只会更新interval
// callback中的参数float dt表示距离上次执行的间隔(秒)。
// target: target of callback,这个callback就绑定到target,
// interval: 每interval秒执行一次,interval=0则每帧执行,可以用scheduleUpdate代替
// repeat: 将执行repeat+1次,repeat=CC_REPEAT_FOREVER表示一直重复执行。
// delay: 第一个schedule在delay秒之后执行,如果=0则在下一帧立即执行。
// paused: 如果pause=true,则只有resume了才会执行。
// key: 用于唯一识别callback
void schedule(const ccSchedulerFunc& callback,
void *target,
float interval,
unsigned int repeat,
float delay,
bool paused,
const std::string& key);
// 下一帧开始,每interval秒执行一次,一直重复。
// repeat: CC_REPEAT_FOREVER
// delay: 0.0
void schedule(const ccSchedulerFunc& callback,
void *target,
float interval,
bool paused,
const std::string& key);
// 参数含义同上,除了:
// selector: 成员函数指针,由于target调用执行selector
如果selector在这之前已经schedule,则只会更新interval
// target: selector所属类的一个对象
void schedule(SEL_SCHEDULE selector,
Ref *target,
float interval,
unsigned int repeat,
float delay,
bool paused);
/** The scheduled method will be called every `interval` seconds for ever.
@param selector The callback function.
@param target The target of the callback function.
@param interval The interval to schedule the callback. If the value is 0, then the callback will be scheduled every frame.
@param paused Whether or not to pause the schedule.
*/
// 下一帧开始,每interval秒执行一次,一直重复。
// repeat: CC_REPEAT_FOREVER
// delay: 0.0
// 其他参数,意义同上
void schedule(SEL_SCHEDULE selector,
Ref *target,
float interval,
bool paused);
scheduleUpdate:逐帧执行
// 每帧执行,schedule callback是target的update成员函数。
// priority越小,优先级越高
// 系统级服务的优先级:
// const int Scheduler::PRIORITY_SYSTEM = INT_MIN;
// 非系统级服务的最低优先级:
// const int Scheduler::PRIORITY_NON_SYSTEM_MIN = PRIORITY_SYSTEM + 1;
template <class T>
void scheduleUpdate(T *target, int priority, bool paused)
{
this->schedulePerFrame([target](float dt){
target->update(dt);
}, target, priority, paused);
}
Node中的schedule
因为schedule是高频使用功能,Node基类中也实现了Scheduler对应的函数,其中的target都是node本身。
// Schedules for lua script.
// handler: The key to search lua function.
// priority: A given priority value.
void scheduleUpdateWithPriorityLua(int handler, int priority);
// 等价于: _scheduler->scheduleUpdate( this, 0, !_running );
void scheduleUpdate(void);
// 等价于: _scheduler->scheduleUpdate( this, priority, !_running );
void scheduleUpdateWithPriority(int priority);
// 类比scheduler中的selector版本
void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
// 等价于上面的schedule( selector, interval, CC_REPEAT_FOREVER, 0.0f );
void schedule(SEL_SCHEDULE selector, float interval);
// delay秒之后执行一次
void scheduleOnce(SEL_SCHEDULE selector, float delay);
// lambada版本
// delay: 第一个schedule在delay秒之后执行,如果=0则在下一帧立即执行。
// key: 用于唯一识别callback
void scheduleOnce(const std::function<void(float)>& callback, float delay, const std::string &key);
// 等价于schedule( selector, 0.0f, CC_REPEAT_FOREVER, 0.0f );
void schedule(SEL_SCHEDULE selector);
// 等价于:
// _scheduler->schedule( callback, this,
// 0, // interval
// !_running, key );
void schedule(const std::function<void(float)>& callback, const std::string &key);
// 等价于:
// _scheduler->schedule( callback, this,
// interval,
// !_running, key );
void schedule(const std::function<void(float)>& callback, float interval, const std::string &key);
// _scheduler->schedule( callback, this, interval, repeat, delay, !_running, key );
void schedule(const std::function<void(float)>& callback, float interval, unsigned int repeat, float delay, const std::string &key);
二、unSchedule
// Unschedules a callback for a key and a given target.
// key: schedule时的key
// target: target to be unscheduled.
void unschedule(const std::string& key, void *target);
// Unschedules a selector for a given target.
// 成员函数的unschedule
void unschedule(SEL_SCHEDULE selector, Ref *target);
// Unschedules the update selector for a given target
void unscheduleUpdate(void *target);
// Unschedules all selectors for a given target.This also includes the "update" selector.
void unscheduleAllForTarget(void *target);
// Unschedules all selectors from all targets.
// You should NEVER call this method, unless you know what you are doing.
void unscheduleAll();
// unschedule all selectors from all targets which 所有优先级小于minPriority的。
// 也就是targetPriority >= minPriority的
// 注意,minPriority必须>=PRIORITY_NON_SYSTEM_MIN,也即不能unschedule系统级schedule
void unscheduleAllWithMinPriority(int minPriority);
三、pause/resume
// 暂停target的所有schedule(selector、update)
// 如果target不存在,啥也不干
void pauseTarget(void *target);
bool isTargetPaused(void *target);
// Pause all selectors from all targets.
// You should NEVER call this method, unless you know what you are doing.
std::set<void*> pauseAllTargets();
// 对比unscheduleAllWithMinPriority
std::set<void*> pauseAllTargetsWithMinPriority(int minPriority);
// 类比上面的pauseTarget
void resumeTarget(void *target);
// Resume selectors on a set of targets.
// This can be useful for undoing a call to pauseAllSelectors.
void resumeTargets(const std::set<void*>& targetsToResume);
四、timeScale:加速
通常,游戏按帧率(真实时间线)进行更新,某些情况下,我们想快进、减慢的效果,可以通过设置scheduler的timescale来实现。
timeScale默认1.0,即保持与帧率相同。大于1.0产生加速效果,小于0产生减慢效果,会影响更新的回调。
相关源码如下:
// 当前timeScale
float Scheduler::getTimeScale() { return _timeScale; }
// timeScale > 1.0,加速
// timeScale = 1.0,正常速度(默认)
// timeScale < 1.0,减速
// 会影响到所有的scheduled selector / action
void Scheduler::setTimeScale(float timeScale) { _timeScale = timeScale; }
五、默认Scheduler
// director在构造的时候就创建了一个Scheduler,用于执行动画
auto defaultScheduler = Director::getInstance()->getScheduler();
相关源码:
bool Director::init()
{
......
_scheduler = new( std::nothrow ) Scheduler(); // defaultScheduler
_actionManager = new( std::nothrow ) ActionManager(); // defaultActionManager
// defaultScheduler来调度defaultActionManager,以最高优先级执行
_scheduler->scheduleUpdate( _actionManager, Scheduler::PRIORITY_SYSTEM, false );
}
六、多Scheduler实例
auto scheduler1 = new(std::nothrow) Scheduler();
auto scheduler2 = new(std::nothrow) Scheduler();
auto scheduler3 = new(std::nothrow) Scheduler();
actionManager1 = new (std::nothrow) ActionManager();
actionManager2 = new (std::nothrow) ActionManager();
actionManager3 = new (std::nothrow) ActionManager();
auto sprite1 = Sprite::create(...);
auto sprite2 = Sprite::create(...);
auto sprite3 = Sprite::create(...);
// schedulern分别调度actionManagern
scheduler1->scheduleUpdate(actionManager1, 0, false);
scheduler2->scheduleUpdate(actionManager2, 0, false);
scheduler3->scheduleUpdate(actionManager3, 0, false);
// 由各自的actionManager执行动画
sprite1->setActionManager(actionManager1);
sprite2->setActionManager(actionManager2);
sprite3->setActionManager(actionManager3);
sprite1->runAction(......);
sprite2->runAction(......);
sprite3->runAction(......);
// 这个三个动画的timeScale也就是执行速度将会不一样。
scheduler1->setTimeScale(0.5f);
scheduler2->setTimeScale(1.0f);
scheduler3->setTimeScale(1.5f);
七、线程安全
Scheduler提供了线程安全调用方法,即函数将在主线程执行。
// function将在cocos2d thread上执行
// function将保存在一个队列,并在下一帧执行。所以如果你立即调用下面的remove,最终将啥都不干。
void performFunctionInCocosThread(std::function<void()> function);
// 立即清空待执行函数的队列
void removeAllFunctionsToBePerformedInCocosThread();