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: 用于唯一识别callbackvoid 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.0void 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: 用于唯一识别callbackvoid 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.// 成员函数的unschedulevoid unschedule(SEL_SCHEDULE selector, Ref *target);// Unschedules the update selector for a given targetvoid 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系统级schedulevoid 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();// 对比unscheduleAllWithMinPrioritystd::set<void*> pauseAllTargetsWithMinPriority(int minPriority);
// 类比上面的pauseTargetvoid 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产生减慢效果,会影响更新的回调。
相关源码如下:
// 当前timeScalefloat Scheduler::getTimeScale() { return _timeScale; }// timeScale > 1.0,加速// timeScale = 1.0,正常速度(默认)// timeScale < 1.0,减速// 会影响到所有的scheduled selector / actionvoid 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分别调度actionManagernscheduler1->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();
