Cocos2d-x ccaction animation Game Development
Original article, reproduced please indicate the source: http://blog.csdn.net/sfh366958228/article/details/38824987
Preface in the previous lecture, we learned about ccaction and the subcategories of ccaction. Although the effect of heartbeat is simple, it is curious. How is it implemented, in this case, we will reveal this secret. The method is very simple, starting from the runaction method call.
Ccnode: runaction
CCAction * CCNode::runAction(CCAction* action){ CCAssert( action != NULL, "Argument must be non-nil"); m_pActionManager->addAction(action, this, !m_bRunning); return action;}
The runaction structure is very simple. An assertion ensures that the action (Action) is not empty. Then, the addaction method of actionmanager is called and the action and target (Execution Action node) are passed) and m_brunning (whether the node is currently running) ccactionmanager: addaction
Void ccactionmanager: addaction (ccaction * paction, ccnode * pTARGET, bool paused) {ccassert (paction! = NULL, ""); // ensure that the action and node are not empty ccassert (pTARGET! = NULL, ""); thashelement * pelement = NULL; // create a hash list element and leave it empty. ccobject * TMP = pTARGET; hash_find_int (m_ptargets, & TMP, pelement ); // find the corresponding hash table item through TMP and return it to pelement if (! Pelement) // If the hash table item {pelement = (thashelement *) calloc (sizeof (* pelement), 1) is not found ); // allocate space for pelement-> paused = paused; // assign the running status of pTARGET to paused pTARGET-> retain () of pelement (); // Add pTARGET reference count pelement-> Target = pTARGET; // assign pTARGET to target hash_add_int (m_ptargets, target, pelement) of pelement ); // Add pelement to the hash table} actionallocwithhashelement (pelement); // allocate the action space ccassert (! Ccarraycontainsobject (pelement-> actions, paction), ""); // determines whether an action is in the action set of an element. Make sure that only once. Ccarrayappendobject (pelement-> actions, paction); // Add the action to the pelement action set paction-> startwithtarget (pTARGET); // set the execution node for the action}
Addaction is a little more complex than runaction, but it is not complicated to view by line code. It is mainly to add the action to the hash table corresponding to the node. If there is no corresponding hash table item, create a new one. The actionallocwithhashelement function ensures that action has a storage space and then stores the paction in the hash table. After everything is okay, call the startwithtarget method of paction to set the node for executing the action.
Ccactionmanager: actionallocwithhashelement
Void ccactionmanager: actionallocwithhashelement (thashelement * pelement) {If (pelement-> actions = NULL) {// determines whether the actions of pelement is blank, if it is null, four spaces are allocated: pelement-> actions = ccarraynew (4);} else if (pelement-> actions-> num = pelement-> actions-> MAX) {// If the pelement capacity is full, double the pelement capacity to ccarraydoublecapacity (pelement-> actions );}}
Ccactionmanager: update is all right. Let's start with the Core update method, which is the reason why the action is actually "dynamic. First, this update method is affiliated with ccactionmanager. According to relevant information, it is called in m_pscheduler-> Update (m_fdeltatime) in the mainloop-> drawscene of ccdisplaylinkctor ctor. M_pschedle is of the ccschedule type. It updates all subsystems of the system, including touch, action, script, and timer. Action is in the list with a priority of <0. We will have the opportunity to study it carefully in the future, and we will continue to return to the update method of ccactionmanager.
Void ccactionmanager: Update (float DT) {for (thashelement * ELT = m_ptargets; ELT! = NULL;) // traverse the hash table {m_pcurrenttarget = ELT; // Save the current hash table item to m_bcurrenttargetsalvaged = false in the m_pcurrenttarget variable; // set the recycle mark of the current node to no if (! M_pcurrenttarget-> paused) // if the item is paused {for (m_pcurrenttarget-> actionindex = 0; m_pcurrenttarget-> actionindex <m_pcurrenttarget-> actions-> num; m_pcurrenttarget-> actionindex ++) {// traverses all actions of the current node m_pcurrenttarget-> currentaction = (ccaction *) m_pcurrenttarget-> actions-> arr [m_pcurrenttarget-> actionindex]; // Save the traversal action to If (m_pcurrenttarget-> currentaction) in m_pcurrenttarget-> currentaction = NULL) {// If the traversal action is null, skip continue ;} m_pcurrenttarget-> currentactionsalvaged = false; // set the recycle tag to no m_pcurrenttarget-> currentaction-> step (DT); // update the playback of the current action if (m_pcurrenttarget-> currentactionsalvaged) // If the recycle tag of the current action is yes, perform the recycle {m_pcurrenttarget-> currentaction-> release ();} else if (m_pcurrenttarget-> currentaction-> isdone ()) // otherwise, determine whether the current node's current action is playing over {m_pcurrenttarget-> currentaction-> stop (); // stop the action ccaction * paction = m_pcurrenttarget-> currentaction; // to release the Action correctly in removeaction, create a temporary variable paction to record the action m_pcurrenttarget-> currentaction = NULL; // set the current action in the current hash table item to null before removeaction; otherwise, the removeaction (paction) cannot be released ); // release the temporary storage action} m_pcurrenttarget-> currentaction = NULL;} // point ELT to the next ELT = (thashelement *) (ELT-> Hh. next); // if the current hash table item is in the recycle state and its action set is empty, delete this hash table item if (m_bcurrenttargetsalvaged & m_pcurrenttarget-> actions-> num = 0) {deletehashelement (m_pcurrenttarget) ;}// set the variable m_pcurrenttarge to m_pcurrenttarget = NULL ;}
In fact, the update code is very simple. It is to traverse the m_ptargets hash list and update the actions in each thashelement one by one. Of course, he will make some judgments, such as whether the action is paused or not ended, to terminate the process, remove it. If everything is normal, call the step method of the action (the concept of polymorphism must be known here, because the step and the subsequent update method are both virtual ).
Ccactioninterval: Step
Void ccactioninterval: Step (float DT) {If (m_bfirsttick) {// If the stream is played for the first time, set the time duration and value to 0. M_bfirsttick = false; m_elapsed = 0;} else {m_elapsed + = DT; // time-consuming and} // call the update function to update the action. The result of the parameter is the result of the time interpolation of the action, which represents the progress of the action. As mentioned earlier, it takes 0 ~ Value between 1. Here min and Max are used to limit the calculation result to 0 ~ 1 This-> Update (max (0, min (1, m_elapsed/MAX (m_fduration, flt_epsilon ))));}
Ccmoveto: Update
Void ccmoveto: Update (float time) {If (m_ptarget) // If the node is not empty {m_ptarget-> setposition (CCP (m_startposition.x + m_delta.x * Time, m_startposition.y + m_delta.y * Time); // set node coordinates }}
Conclusion The implementation principle of an action is over. If you are interested, you can also look at the jump and scale implementation methods. The basic animation implementation methods are similar.
Analysis of cocos2d-x implementation of action: http://www.linuxidc.com/Linux/2013-04/82436.htm
2) Cocos2d-x 2.0 actions (III): http://bbs.9ria.com/thread-198822-1-1.html
3) Cocos2d-x 2.0 actions one of the three axes: http://blog.csdn.net/honghaier/article/details/8197892
Cocos2d-x Study Notes (7) Analysis of ccaction Principle