Cocos2d-x 3.X里有三种调度器,分别为默认调度器scheduleUpdate(),自定义调度器schedule(),和单次调度器scheduleOnce()。它们都是Node类成员函数。它们又都分别调用了单例模式的Scheduler类里面对应的三个调度器。所以我们既可以通过Node里面的调度器来定时调度某个事件,也可以直接通过总调度器Scheduler来调度事件。但是要注意两者的参数(调度对象)不同。
例如,如果某个Node子类(如图层,精灵等)对象调用的是Node里面的scheduleUpdate()(没有参数),它首先会去调度子类中的update()函数,如果子类中没有update(),它就会调度Node里面的update()函数:
CCNode.cpp
// override me void Node::update(float fDelta) { #if CC_ENABLE_SCRIPT_BINDING if (0 != _updateScriptHandler) { //only lua use SchedulerScriptData data(_updateScriptHandler,fDelta); ScriptEvent event(kScheduleEvent,&data); ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event); } #endif if (_componentContainer && !_componentContainer->isEmpty()) { _componentContainer->visit(fDelta); } }
在这里面我们看到它调用了componentContainer。控制器ComController里面的update()就是在这里被调用的。但是(第二遍),如果update()被子类重写,那么子类对象调度的就是子类的update()函数,同时ComController里面的update()就不再被调用,除非把这部分也重写进去,这一点要非常注意。
如果我们直接调用Scheduler里面的scheduleUpdate(T* target,int priority,bool paused),那么必须指定调度对象,它会启动指定对象中的update()函数。
在这里顺便提一下面向对象编程时要注意的地方:父类对象只能调用父类函数,子类对象调用(即使是通过父类函数间接调用)的首先是子类函数,除非子类中没有定义才去调用父类函数。在上面这个例子中某个子类对象先调用了父类Node里面的scheduleUpate()函数(子类也可以重写该函数),而该函数又可以调用子类中重写的update()函数(此时update必须为虚函数,否则在父类中就找不到声明了)(第三遍)。
父类中的纯虚函数只能被子类对象调用,只不过当我们把子类对象的类型转化为父类类型时,该对象仍然可以调用子类中定义的(父类中声明的)纯虚函数,但是它本质上还是子类对象(从内存分配来看)。
在使用scheduleUpdate()时要注意两个问题:
1)怎么调用调度器
scheduleUpdate()可以在某个场景或图层中直接手动调用。但是注意如果在使用ComController时,以下两个函数也会自动调用该调度器:
CCNode.cpp
bool Node::addComponent(Component *component) { // lazy alloc if (!_componentContainer) _componentContainer = new (std::nothrow) ComponentContainer(this); // should enable schedule update,then all components can receive this call back scheduleUpdate(); return _componentContainer->add(component); }
void ComController::onEnter() { if (_owner != nullptr) { _owner->scheduleUpdate(); } }
2)调度哪个update()
前面已经提到过,要注意调度的是Node子类(如图层,精灵等)中的update()还是ComController里面的update()(通过Node中update()调用)。
水平有限,如有不妥,欢迎拍砖!