标签:
Cocos2d-x 3.2:定时器的使用和原理探究(3)
上篇文章分析到了定时器的定义,这篇的重点就是定时器是如何运行起来的。
1.从main中寻找定时器的回调
讲定时器的运行,就不得不触及到cocos2dx的main函数了,因为定时器是主线程上运行的,并不是单独线程的,所以它的调用必然会在main函数中,每帧调用。
以下代码就是win32平台下的main函数
- int APIENTRY _tWinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPTSTR lpCmdLine,
- int nCmdShow)
- {
- UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
-
-
- AppDelegate app;
- return Application::getInstance()->run();
- }
直接调用了run函数,直接进入到run中
- int Application::run()
- {
- while(!glview->windowShouldClose())
- {
- QueryPerformanceCounter(&nNow);
- if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
- {
- nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);
-
- director->mainLoop();
- glview->pollEvents();
- }
- else
- {
- Sleep(1);
- }
- }
- return 0;
- }
run函数中其他不相关的调用我已经去掉了,可以看到mainLoop函数才是真正的主循环
- void DisplayLinkDirector::mainLoop()
- {
-
- if (! _invalid)
- {
- drawScene();
- }
- }
看到这里实际上也是调用drawScene函数
- void Director::drawScene()
- {
- if (! _paused)
- {
- _scheduler->update(_deltaTime);
- _eventDispatcher->dispatchEvent(_eventAfterUpdate);
- }
-
- }
drawScene要做的事情很多,我将绘制部分都去掉了,值得注意的是 绘制场景会在定时器之后才执行。
这里可以看到,实际上执行的就是定时器的update函数,那么这个update函数中究竟执行了什么东西呢?
2.定时器的update函数
首先来看看Update的代码
- void Scheduler::update(float dt)
- {
- _updateHashLocked = true;
-
- if (_timeScale != 1.0f)
- {
- dt *= _timeScale;
- }
-
-
-
-
-
- tListEntry *entry, *tmp;
-
-
- DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
- {
- if ((! entry->paused) && (! entry->markedForDeletion))
- {
- entry->callback(dt);
- }
- }
-
-
- DL_FOREACH_SAFE(_updates0List, entry, tmp)
- {
- if ((! entry->paused) && (! entry->markedForDeletion))
- {
- entry->callback(dt);
- }
- }
-
-
- DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
- {
- if ((! entry->paused) && (! entry->markedForDeletion))
- {
- entry->callback(dt);
- }
- }
-
-
- for (tHashTimerEntry *elt = _hashForTimers; elt != nullptr; )
- {
- _currentTarget = elt;
- _currentTargetSalvaged = false;
-
- if (! _currentTarget->paused)
- {
-
- for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
- {
- elt->currentTimer = (Timer*)(elt->timers->arr[elt->timerIndex]);
- elt->currentTimerSalvaged = false;
-
-
- elt->currentTimer->update(dt);
-
- if (elt->currentTimerSalvaged)
- {
-
- elt->currentTimer->release();
- }
-
- elt->currentTimer = nullptr;
- }
- }
-
-
- elt = (tHashTimerEntry *)elt->hh.next;
-
-
- if (_currentTargetSalvaged && _currentTarget->timers->num == 0)
- {
- removeHashElement(_currentTarget);
- }
- }
-
-
- DL_FOREACH_SAFE(_updatesNegList, entry, tmp)
- {
- if (entry->markedForDeletion)
- {
- this->removeUpdateFromHash(entry);
- }
- }
-
-
- DL_FOREACH_SAFE(_updates0List, entry, tmp)
- {
- if (entry->markedForDeletion)
- {
- this->removeUpdateFromHash(entry);
- }
- }
-
-
- DL_FOREACH_SAFE(_updatesPosList, entry, tmp)
- {
- if (entry->markedForDeletion)
- {
- this->removeUpdateFromHash(entry);
- }
- }
-
- _updateHashLocked = false;
- _currentTarget = nullptr;
- }
有三个部分值得注意的:
- update定时器优先调用
- update定时器中优先级越低的越优先调用
- 自定义定时器的回调在elt->currentTimer->update(dt);中执行
关于第三点,我们继续分析这个update函数
- void Timer::update(float dt)
- {
-
- if (_elapsed == -1)
- {
- _elapsed = 0;
- _timesExecuted = 0;
- }
- else
- {
- if (_runForever && !_useDelay)
- {
- _elapsed += dt;
- if (_elapsed >= _interval)
- {
- trigger();
-
- _elapsed = 0;
- }
- }
- else
- {
- _elapsed += dt;
- if (_useDelay)
- {
- if( _elapsed >= _delay )
- {
- trigger();
-
- _elapsed = _elapsed - _delay;
- _timesExecuted += 1;
- _useDelay = false;
- }
- }
- else
- {
- if (_elapsed >= _interval)
- {
- trigger();
-
- _elapsed = 0;
- _timesExecuted += 1;
-
- }
- }
-
-
- if (!_runForever && _timesExecuted > _repeat)
- {
- cancel();
- }
- }
- }
- }
这一大段代码的逻辑非常清晰,延时函数主要分为,永远循环的延时函数,有限循环的延迟函数;而有限循环的延迟函数里面根据优化的不同可以分为每帧调用的和固定时间调用的。上述代码就是根据这个分类进行优化的。
实际上核心的函数在
第一个函数是真正的回调执行的函数,第二个函数是去掉执行的函数
- void TimerTargetSelector::trigger()
- {
- if (_target && _selector)
- {
- (_target->*_selector)(_elapsed);
- }
- }
-
- void TimerTargetSelector::cancel()
- {
- _scheduler->unschedule(_selector, _target);
- }
以上就是定时器的实现原理分析的全过程,定时器的实现在文章中我感觉还是说的不是很清楚。真正去代码中自己走一遍应该会更加明了,对以后的应用也会更得心应手。
Cocos2d-x 3.2:定时器的使用和原理探究(3)
标签:
原文地址:http://www.cnblogs.com/dudu580231/p/4560365.html