cocos提供了灵活的机制来实现游戏对象的状态更新,我们可以向scheduler注册回调函数来实现更新逻辑,scheduler提供了两种回调更新机制:

一、schedule

schedule:自定义间隔

注册自定义回调,需要用到Timer对象进行计时,需要花费更多内存和计算,且不能指定优先级,谨慎使用。

  1. // callback: 重复执行的函数,如果callback已经被schedule,则只会更新interval
  2. // callback中的参数float dt表示距离上次执行的间隔(秒)。
  3. // target: target of callback,这个callback就绑定到target,
  4. // interval: 每interval秒执行一次,interval=0则每帧执行,可以用scheduleUpdate代替
  5. // repeat: 将执行repeat+1次,repeat=CC_REPEAT_FOREVER表示一直重复执行。
  6. // delay: 第一个schedule在delay秒之后执行,如果=0则在下一帧立即执行。
  7. // paused: 如果pause=true,则只有resume了才会执行。
  8. // key: 用于唯一识别callback
  9. void schedule(const ccSchedulerFunc& callback,
  10. void *target,
  11. float interval,
  12. unsigned int repeat,
  13. float delay,
  14. bool paused,
  15. const std::string& key);
  16. // 下一帧开始,每interval秒执行一次,一直重复。
  17. // repeat: CC_REPEAT_FOREVER
  18. // delay: 0.0
  19. void schedule(const ccSchedulerFunc& callback,
  20. void *target,
  21. float interval,
  22. bool paused,
  23. const std::string& key);
  24. // 参数含义同上,除了:
  25. // selector: 成员函数指针,由于target调用执行selector
  26. 如果selector在这之前已经schedule,则只会更新interval
  27. // target: selector所属类的一个对象
  28. void schedule(SEL_SCHEDULE selector,
  29. Ref *target,
  30. float interval,
  31. unsigned int repeat,
  32. float delay,
  33. bool paused);
  34. /** The scheduled method will be called every `interval` seconds for ever.
  35. @param selector The callback function.
  36. @param target The target of the callback function.
  37. @param interval The interval to schedule the callback. If the value is 0, then the callback will be scheduled every frame.
  38. @param paused Whether or not to pause the schedule.
  39. */
  40. // 下一帧开始,每interval秒执行一次,一直重复。
  41. // repeat: CC_REPEAT_FOREVER
  42. // delay: 0.0
  43. // 其他参数,意义同上
  44. void schedule(SEL_SCHEDULE selector,
  45. Ref *target,
  46. float interval,
  47. bool paused);

scheduleUpdate:逐帧执行

  1. // 每帧执行,schedule callback是target的update成员函数。
  2. // priority越小,优先级越高
  3. // 系统级服务的优先级:
  4. // const int Scheduler::PRIORITY_SYSTEM = INT_MIN;
  5. // 非系统级服务的最低优先级:
  6. // const int Scheduler::PRIORITY_NON_SYSTEM_MIN = PRIORITY_SYSTEM + 1;
  7. template <class T>
  8. void scheduleUpdate(T *target, int priority, bool paused)
  9. {
  10. this->schedulePerFrame([target](float dt){
  11. target->update(dt);
  12. }, target, priority, paused);
  13. }

Node中的schedule

因为schedule是高频使用功能,Node基类中也实现了Scheduler对应的函数,其中的target都是node本身。

  1. // Schedules for lua script.
  2. // handler: The key to search lua function.
  3. // priority: A given priority value.
  4. void scheduleUpdateWithPriorityLua(int handler, int priority);
  5. // 等价于: _scheduler->scheduleUpdate( this, 0, !_running );
  6. void scheduleUpdate(void);
  7. // 等价于: _scheduler->scheduleUpdate( this, priority, !_running );
  8. void scheduleUpdateWithPriority(int priority);
  9. // 类比scheduler中的selector版本
  10. void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
  11. // 等价于上面的schedule( selector, interval, CC_REPEAT_FOREVER, 0.0f );
  12. void schedule(SEL_SCHEDULE selector, float interval);
  13. // delay秒之后执行一次
  14. void scheduleOnce(SEL_SCHEDULE selector, float delay);
  15. // lambada版本
  16. // delay: 第一个schedule在delay秒之后执行,如果=0则在下一帧立即执行。
  17. // key: 用于唯一识别callback
  18. void scheduleOnce(const std::function<void(float)>& callback, float delay, const std::string &key);
  19. // 等价于schedule( selector, 0.0f, CC_REPEAT_FOREVER, 0.0f );
  20. void schedule(SEL_SCHEDULE selector);
  21. // 等价于:
  22. // _scheduler->schedule( callback, this,
  23. // 0, // interval
  24. // !_running, key );
  25. void schedule(const std::function<void(float)>& callback, const std::string &key);
  26. // 等价于:
  27. // _scheduler->schedule( callback, this,
  28. // interval,
  29. // !_running, key );
  30. void schedule(const std::function<void(float)>& callback, float interval, const std::string &key);
  31. // _scheduler->schedule( callback, this, interval, repeat, delay, !_running, key );
  32. void schedule(const std::function<void(float)>& callback, float interval, unsigned int repeat, float delay, const std::string &key);

二、unSchedule

  1. // Unschedules a callback for a key and a given target.
  2. // key: schedule时的key
  3. // target: target to be unscheduled.
  4. void unschedule(const std::string& key, void *target);
  5. // Unschedules a selector for a given target.
  6. // 成员函数的unschedule
  7. void unschedule(SEL_SCHEDULE selector, Ref *target);
  8. // Unschedules the update selector for a given target
  9. void unscheduleUpdate(void *target);
  10. // Unschedules all selectors for a given target.This also includes the "update" selector.
  11. void unscheduleAllForTarget(void *target);
  12. // Unschedules all selectors from all targets.
  13. // You should NEVER call this method, unless you know what you are doing.
  14. void unscheduleAll();
  15. // unschedule all selectors from all targets which 所有优先级小于minPriority的。
  16. // 也就是targetPriority >= minPriority的
  17. // 注意,minPriority必须>=PRIORITY_NON_SYSTEM_MIN,也即不能unschedule系统级schedule
  18. void unscheduleAllWithMinPriority(int minPriority);

三、pause/resume

  1. // 暂停target的所有schedule(selector、update)
  2. // 如果target不存在,啥也不干
  3. void pauseTarget(void *target);
  4. bool isTargetPaused(void *target);
  5. // Pause all selectors from all targets.
  6. // You should NEVER call this method, unless you know what you are doing.
  7. std::set<void*> pauseAllTargets();
  8. // 对比unscheduleAllWithMinPriority
  9. std::set<void*> pauseAllTargetsWithMinPriority(int minPriority);
  1. // 类比上面的pauseTarget
  2. void resumeTarget(void *target);
  3. // Resume selectors on a set of targets.
  4. // This can be useful for undoing a call to pauseAllSelectors.
  5. void resumeTargets(const std::set<void*>& targetsToResume);

四、timeScale:加速

通常,游戏按帧率(真实时间线)进行更新,某些情况下,我们想快进、减慢的效果,可以通过设置scheduler的timescale来实现。
timeScale默认1.0,即保持与帧率相同。大于1.0产生加速效果,小于0产生减慢效果,会影响更新的回调。
相关源码如下:

  1. // 当前timeScale
  2. float Scheduler::getTimeScale() { return _timeScale; }
  3. // timeScale > 1.0,加速
  4. // timeScale = 1.0,正常速度(默认)
  5. // timeScale < 1.0,减速
  6. // 会影响到所有的scheduled selector / action
  7. void Scheduler::setTimeScale(float timeScale) { _timeScale = timeScale; }

五、默认Scheduler

  1. // director在构造的时候就创建了一个Scheduler,用于执行动画
  2. auto defaultScheduler = Director::getInstance()->getScheduler();

相关源码:

  1. bool Director::init()
  2. {
  3. ......
  4. _scheduler = new( std::nothrow ) Scheduler(); // defaultScheduler
  5. _actionManager = new( std::nothrow ) ActionManager(); // defaultActionManager
  6. // defaultScheduler来调度defaultActionManager,以最高优先级执行
  7. _scheduler->scheduleUpdate( _actionManager, Scheduler::PRIORITY_SYSTEM, false );
  8. }

六、多Scheduler实例

  1. auto scheduler1 = new(std::nothrow) Scheduler();
  2. auto scheduler2 = new(std::nothrow) Scheduler();
  3. auto scheduler3 = new(std::nothrow) Scheduler();
  4. actionManager1 = new (std::nothrow) ActionManager();
  5. actionManager2 = new (std::nothrow) ActionManager();
  6. actionManager3 = new (std::nothrow) ActionManager();
  7. auto sprite1 = Sprite::create(...);
  8. auto sprite2 = Sprite::create(...);
  9. auto sprite3 = Sprite::create(...);
  10. // schedulern分别调度actionManagern
  11. scheduler1->scheduleUpdate(actionManager1, 0, false);
  12. scheduler2->scheduleUpdate(actionManager2, 0, false);
  13. scheduler3->scheduleUpdate(actionManager3, 0, false);
  14. // 由各自的actionManager执行动画
  15. sprite1->setActionManager(actionManager1);
  16. sprite2->setActionManager(actionManager2);
  17. sprite3->setActionManager(actionManager3);
  18. sprite1->runAction(......);
  19. sprite2->runAction(......);
  20. sprite3->runAction(......);
  21. // 这个三个动画的timeScale也就是执行速度将会不一样。
  22. scheduler1->setTimeScale(0.5f);
  23. scheduler2->setTimeScale(1.0f);
  24. scheduler3->setTimeScale(1.5f);

七、线程安全

Scheduler提供了线程安全调用方法,即函数将在主线程执行。

  1. // function将在cocos2d thread上执行
  2. // function将保存在一个队列,并在下一帧执行。所以如果你立即调用下面的remove,最终将啥都不干。
  3. void performFunctionInCocosThread(std::function<void()> function);
  4. // 立即清空待执行函数的队列
  5. void removeAllFunctionsToBePerformedInCocosThread();