The previous article analyzed the definition of the timer. The point of this article is how the timer is executed.
1. Find the callback for the timer from main
Speaking of the execution of the timer, you have to touch the main function of the COCOS2DX, because the timer is executed on the main thread. is not a separate thread. So its invocation is bound to be called in the main function, every frame.
The following code is the main function under the Win32 platform
int Apientry _tWinMain (hinstance hinstance, hinstance hprevinstance, LPTSTR lpcmdline, int nCmdShow) { unreferenced_parameter (hprevinstance); Unreferenced_parameter (lpcmdline); Create the application instance appdelegate app; Return Application::getinstance ()->run ();}
Call the run function directly and go directly to the 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 ();//See here glview->pollevents (); } else { Sleep (1); } } return 0;}
Other unrelated calls in the run function I've removed, and I can see that the Mainloop function is the real main loop.
void Displaylinkdirector::mainloop () { //Do other unrelated things if (! _invalid) { drawscene (); }}
See here is actually calling the Drawscene function
void Director::d rawscene () { if (! _paused) { _scheduler->update (_deltatime); _eventdispatcher->dispatchevent (_eventafterupdate); } Before drawing}
DrawsceneThere's so much to do, I'm going to get rid of the drawing part. It is important to note that the drawing scene will not run until after the timer.
As you can see here, the update function of the timer is actually running. So what exactly is running in this update function?
2. The update function of the timer
First look at the code for update
Main loopvoid scheduler::update (float dt) {_updatehashlocked = true; if (_timescale! = 1.0f) {dt *= _timescale; }////Timer callback//Tlistentry *entry, *tmp; Queues with priority less than 0 in the update timer first run Dl_foreach_safe (_updatesneglist, entry, TMP) {if ((! entry->paused) && (! entry->markedfordeletion)) {entry->callback (dt); }}//Next is the priority equals 0 Dl_foreach_safe (_updates0list, entry, TMP) {if ((! entry->paused) && (! entry->markedfordeletion)) {entry->callback (dt); }}//finally is greater than 0 dl_foreach_safe (_updatesposlist, entry, TMP) {if ((! entry->paused) && (! en try->markedfordeletion)) {entry->callback (dt); }}//Here The loop is itself defined timer for (thashtimerentry *elt = _hashfortimers; ELT! = nullptr;) {_currenttarget = ELT; _currenttargetsalvaged = false; if (! _currenttarget->paused) {//Traverse all timers attached to the current object for (Elt->timerindex = 0; Elt->timerindex < Elt->timer s->num; + + (Elt->timerindex)) {Elt->currenttimer = (timer*) (Elt->timers->arr[elt->timerin Dex]); elt->currenttimersalvaged = false;//actually run the real callback elt->currenttimer->update (DT) here; if (elt->currenttimersalvaged) {//When the timer finishes the task. Should release the Elt->currenttimer->release (); } Elt->currenttimer = nullptr; }}//point to the next object of the list ELT = (Thashtimerentry *) elt->hh.next; When all the timers for the object have been run. And the object's attached timer is empty, the object is removed from the hash list if (_currenttargetsalvaged && _currenttarget->timers->num = = 0) { Removehashelement (_currenttarget); }}//Remove all the update timer elements marked for deletion with a priority of less than 0 dl_foreach_safe (_updatesneglist, entry, TMP) {if(entry->markedfordeletion) {This->removeupdatefromhash (entry); The update timer element Dl_foreach_safe (_updates0list, entry, TMP) {if (ENTRY->MARKEDFO)}}//Removed all marked for deletion with priority equal to 0 rdeletion) {This->removeupdatefromhash (entry); }}//Remove all the update timer elements marked for deletion with a priority greater than 0 Dl_foreach_safe (_updatesposlist, entry, TMP) {if (entry->marked fordeletion) {This->removeupdatefromhash (entry); }} _updatehashlocked = false; _currenttarget = nullptr;}
There are three parts worth noting:
- Update Timer Priority call
- The lower the priority of the update timer, the higher the priority call
- Self-defined timer callback in elt->currenttimer->update (DT);
On the 3rd, we continue to analyze this update function
void Timer::update (float dt) {///First run will enter into this if initialize if (_elapsed = =-1) {_elapsed = 0;//elapsed Time _timesexe cuted = 0;//Initialization repeated} else {if (_runforever &&!_usedelay) {//cyclic delay function _elapsed + = DT; if (_elapsed >= _interval) {trigger ();//Real callback _elapsed = 0; }} else {//advanced usage _elapsed + = DT; if (_usedelay)//delay {if (_elapsed >= _delay) {trigger (); /Real Callback _elapsed = _elapsed-_delay; _timesexecuted + = 1; _usedelay = false; }} else//calls {if (_elapsed >= _interval) per frame { Trigger ();//Real callback _elapsed = 0; _timesexecuted + = 1; }}//callback complete, run Cancel function if (!_runforever && _timesexecuted > _repeat) {//unschedule timer cancel (); } } }}
The logic of this large piece of code is clear. The delay function is mainly divided into the delay function of the perpetual cycle and the delay function of the finite cycle. The delay function of the finite loop can be divided into the call of each frame and the fixed time according to the difference of the optimization. The above code is optimized according to this classification.
In fact, the core function
Trigger (); cancel ();
The first function is a real callback function, and the second function is to remove the running function.
void Timertargetselector::trigger () { if (_target && _selector) { (_target->*_selector) (_ elapsed);} } void Timertargetselector::cancel () { _scheduler->unschedule (_selector, _target);}
The above is the implementation of the principle of the timer analysis of the whole process, the actual timer is now in the article I feel or say is not very clear. Really go to the code to go through their own should be more clear, for future applications will be more handy.
"In-depth understanding of the use and principles of the Cocos2d-x 3.x" timer (scheduler) (3)