CCActionManager(动作管理器)

#ifndef __ACTION_CCACTION_MANAGER_H__

#define __ACTION_CCACTION_MANAGER_H__


#include "CCAction.h"

#include "cocoa/CCArray.h"

#include "cocoa/CCObject.h"


NS_CC_BEGIN

//要用到CCSet类进行存储  

class CCSet;

//使用哈希表元素  

struct _hashElement;

//

 @brief CCActionManager is a singleton that manages all the actions.

 Normally you won't need to use this singleton directly. 99% of the cases you will use the CCNode interface,

 which uses this singleton.

 But there are some cases where you might need to use this singleton.

 Examples:

    - When you want to run an action where the target is different from a CCNode. 

    - When you want to pause / resume the actions

 ///

class CC_DLL CCActionManager : public CCObject

{

public:

    CCActionManager(void);

    ~CCActionManager(void);


    // actions

    ///

   Adds an action with a target. 

     If the target is already present, then the action will be added to the existing target.

     If the target is not present, a new instance of this target will be created either paused or not, and the action will be added to the newly created target.

     When the target is paused, the queued actions won't be 'ticked'.

    ///

    void addAction(CCAction *pAction, CCNode *pTarget, bool paused);//3、是否立即播放


 // Removes all actions from all the targets.

    void removeAllActions(void);


  //Removes all actions from a certain target.

    void removeAllActionsFromTarget(CCObject *pTarget);


   // Removes an action given an action reference.

    void removeAction(CCAction *pAction);


   //Removes an action given its tag and the target 

    void removeActionByTag(unsigned int tag, CCObject *pTarget);


    CCAction* getActionByTag(unsigned int tag, CCObject *pTarget);


//返回指定目标所应用的动作数量  

    unsigned int numberOfRunningActionsInTarget(CCObject *pTarget);

   

//停止指定目标的所有的动作。

    void pauseTarget(CCObject *pTarget);


//继续播放指定目标的所有动作  

    void resumeTarget(CCObject *pTarget);

    

  //暂停所有正在动行的动作,并将这些暂停的动作存入CCSet中返回。  

    CCSet* pauseAllRunningActions();

    

 

  //继结播放CCSet中的所有动作。   

    void resumeTargets(CCSet *targetsToResume);


protected:

    void removeActionAtIndex(unsigned int uIndex, struct _hashElement *pElement);


    void deleteHashElement(struct _hashElement *pElement);

//为pElement申请内存存放动画集。  

    void actionAllocWithHashElement(struct _hashElement *pElement);

    

    //这个函数重要了~,它在每一帧被调用,通过传入的时间流逝长度传给每一个非暂停的动作进行相应的更新

    void update(float dt);


protected:

    struct _hashElement    *m_pTargets;

    struct _hashElement    *m_pCurrentTarget;

    bool            m_bCurrentTargetSalvaged;

};


// end of actions group

/// @}


NS_CC_END


#endif // __ACTION_CCACTION_MANAGER_H__


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.cpp

  1. #include "CCActionManager.h"  
  2. #include "base_nodes/CCNode.h"  
  3. #include "CCScheduler.h"  
  4. #include "ccMacros.h"  
  5. #include "support/data_support/ccCArray.h"  
  6. #include "support/data_support/uthash.h"  
  7. #include "cocoa/CCSet.h"  
  8. //使用Cocos2d命名空间  
  9. NS_CC_BEGIN  
  10. //这里定义了一个哈希表项结构,用于存储一个演员的动画集相关信息。  
  11. typedef struct _hashElement  
  12. {  
  13.     struct _ccArray             *actions;   //动画集  
  14.     CCObject                    *target;    //演员的指针  
  15.     unsigned int                actionIndex;//动画在动画集中的索引。  
  16.     CCAction                    *currentAction;//当前正在播放的动画  
  17.     bool                        currentActionSalvaged;//当前动画是否被回收。  
  18.     bool                        paused;//是否停止播放。  
  19.     UT_hash_handle                hh;//哈希表查询句柄。  
  20. } tHashElement;  
  21.   
  22. //构造函数  
  23. CCActionManager::CCActionManager(void)  
  24. : m_pTargets(NULL),   
  25.   m_pCurrentTarget(NULL),  
  26.   m_bCurrentTargetSalvaged(false)  
  27. {  
  28.   
  29. }  
  30.   
  31. //析构函数  
  32. CCActionManager::~CCActionManager(void)  
  33. {  
  34.     CCLOGINFO("cocos2d: deallocing %p"this);  
  35.     //清空所有的动画  
  36.     removeAllActions();  
  37. }  
  38.   
  39. //删除相应的哈希表项  
  40. void CCActionManager::deleteHashElement(tHashElement *pElement)  
  41. {  
  42.     //释放pElement存储的动画集  
  43.     ccArrayFree(pElement->actions);  
  44.     //从哈希表m_pTargets中删除pElement项  
  45.     HASH_DEL(m_pTargets, pElement);  
  46.     //释放pElement  
  47.     pElement->target->release();  
  48.     free(pElement);  
  49. }  
  50. //为哈希表项pElement申请内存,以存放动画集  
  51. void CCActionManager::actionAllocWithHashElement(tHashElement *pElement)  
  52. {  
  53.     // 默认每个哈希表项存四个动画,所以如果当前哈希表项的动画集为空,则为其申请可存放4个动画指针的内存大小。  
  54.     if (pElement->actions == NULL)  
  55.     {  
  56.         pElement->actions = ccArrayNew(4);  
  57.     }else   
  58.     if (pElement->actions->num == pElement->actions->max)  
  59.     {   //如果哈希表项的动作集需要扩大,则扩增为原来的2倍直至达到最大容量。  
  60.         ccArrayDoubleCapacity(pElement->actions);  
  61.     }  
  62.   
  63. }  
  64. //从哈希表项的动画集中移除掉指定的动画。  
  65. void CCActionManager::removeActionAtIndex(unsigned int uIndex, tHashElement *pElement)  
  66. {  
  67.     //通过参数uIndex找到哈希表项的动画集中的对应动画。  
  68.     CCAction *pAction = (CCAction*)pElement->actions->arr[uIndex];  
  69.   
  70.     //如果当前动画正在播放中而且回收标记为否  
  71.     if (pAction == pElement->currentAction && (! pElement->currentActionSalvaged))  
  72.     {  
  73.         //引用计数器加1,代表被管理器使用中。  
  74.         pElement->currentAction->retain();  
  75.         //设其回收标记为true。  
  76.         pElement->currentActionSalvaged = true;  
  77.     }  
  78.     //从动画集中移除指定位置的动画。  
  79.     ccArrayRemoveObjectAtIndex(pElement->actions, uIndex, true);  
  80.     //  
  81.     if (pElement->actionIndex >= uIndex)  
  82.     {  
  83.         pElement->actionIndex--;  
  84.     }  
  85.     //如果pElement的动画集的数量为0  
  86.     if (pElement->actions->num == 0)  
  87.     {  
  88.          //如果当前正有演员在演示本动画,那么先将其要回收标记设为true 。  
  89.         if (m_pCurrentTarget == pElement)  
  90.         {  
  91.             m_bCurrentTargetSalvaged = true;  
  92.         }  
  93.         else  
  94.         {  
  95.               //否则立即释放  
  96.             deleteHashElement(pElement);  
  97.         }  
  98.     }  
  99. }  
  100. //暂停目标演员身上的所有动画  
  101. void CCActionManager::pauseTarget(CCObject *pTarget)  
  102. {  
  103.     //声明一个哈希表项指针  
  104.     tHashElement *pElement = NULL;  
  105.     //通过哈希表处理相关宏找到对应的哈希表项。  
  106.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  107.     //如果找到,则将其暂停开关变量设为true  
  108.     if (pElement)  
  109.     {  
  110.         pElement->paused = true;  
  111.     }  
  112. }  
  113. //继续目标演员身上的所有动画  
  114. void CCActionManager::resumeTarget(CCObject *pTarget)  
  115. {  
  116.     //定义一个哈希表项指针变量并置空。  
  117.     tHashElement *pElement = NULL;  
  118.     //通过哈希表处理相关宏找到对应的哈希表项。  
  119.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  120.     //如果找到,则将其暂停开关变量设为false,使其处于播放状态。  
  121.     if (pElement)  
  122.     {  
  123.         pElement->paused = false;  
  124.     }  
  125. }  
  126. //暂停所有正在播放中的动画  
  127. CCSet* CCActionManager::pauseAllRunningActions()  
  128. {  
  129.     //创建一个CCSet容器  
  130.     CCSet *idsWithActions = new CCSet();  
  131.     //此容器交由内存管理器进行内存的最后释放。无需手动delete。  
  132.     idsWithActions->autorelease();  
  133.     //遍历所有的哈希表项  
  134.     for (tHashElement *element=m_pTargets; element != NULL; element = (tHashElement *)element->hh.next)   
  135.     {  
  136.         //如果当前遍历位置的哈希表项处于播放状态,设置其暂停并将其放入CCSet容器中。  
  137.         if (! element->paused)   
  138.         {  
  139.             element->paused = true;  
  140.             idsWithActions->addObject(element->target);  
  141.         }  
  142.     }      
  143.     //返回容器。  
  144.     return idsWithActions;  
  145. }  
  146. //继续播放容器中的所有动画  
  147. void CCActionManager::resumeTargets(cocos2d::CCSet *targetsToResume)  
  148. {      
  149.     //定义CCSet容器的迭代器。之后遍历参数容器。将每一个项设为播放状态。  
  150.     CCSetIterator iter;  
  151.     for (iter = targetsToResume->begin(); iter != targetsToResume->end(); ++iter)  
  152.     {  
  153.         resumeTarget(*iter);  
  154.     }  
  155. }  
  156.   
  157. //将一个动画和应用此动画的演员,以及当前动画是否处于暂停状态信息存入管理器中。  
  158. void CCActionManager::addAction(CCAction *pAction, CCNode *pTarget, bool paused)  
  159. {  
  160.     //有效性判断。  
  161.     CCAssert(pAction != NULL, "");  
  162.     CCAssert(pTarget != NULL, "");  
  163.     //定义一个哈希表项的指针变量并置空。  
  164.     tHashElement *pElement = NULL;  
  165.     //将pTarget转为一个CCObject类型的指针。用于哈希表查询。  
  166.     CCObject *tmp = pTarget;  
  167.     //通过这个指针,找到对应的哈希表项返回给pElement;  
  168.     HASH_FIND_INT(m_pTargets, &tmp, pElement);  
  169.     //如果找不到。则代表新加入的哈希表项。则申请内存创建此哈希表项,并将其加入哈希表中。  
  170.     if (! pElement)  
  171.     {  
  172.         //创建一个哈希表项  
  173.         pElement = (tHashElement*)calloc(sizeof(*pElement), 1);  
  174.          //设置其是否为暂停状态。  
  175.         pElement->paused = paused;  
  176.          //引用计数器加1,代表被管理器使用中。  
  177.         pTarget->retain();  
  178.          //设置哈希表项中的演员为参数指定的演员。  
  179.         pElement->target = pTarget;  
  180.          //调用哈希表处理宏将哈希表项加入哈希表。  
  181.         HASH_ADD_INT(m_pTargets, target, pElement);  
  182.     }  
  183.     //为哈希表项pElement申请内存,以存放动画集  
  184.      actionAllocWithHashElement(pElement);  
  185.     //判断pAction是否在pElement的动画集中。确保只放入一次。  
  186.      CCAssert(! ccArrayContainsObject(pElement->actions, pAction), "");  
  187.     //将pAction放入pElement的动画集中。  
  188.      ccArrayAppendObject(pElement->actions, pAction);  
  189.      //设置是哪个CCNode要进行当前动画  
  190.      pAction->startWithTarget(pTarget);  
  191. }  
  192.   
  193. //清除所有的动画  
  194. void CCActionManager::removeAllActions(void)  
  195. {  
  196.     //遍历哈希表中的所有项  
  197.     for (tHashElement *pElement = m_pTargets; pElement != NULL; )  
  198.     {  
  199.         //取得对应项信息中的演员指针  
  200.         CCObject *pTarget = pElement->target;  
  201.         //这里是用于继续循环的处理,将当前项指向下一个哈希表项。  
  202.         pElement = (tHashElement*)pElement->hh.next;  
  203.         //释放演员的所有动画  
  204.         removeAllActionsFromTarget(pTarget);  
  205.     }  
  206. }  
  207.   
  208. //删除对应演员的所有动画  
  209. void CCActionManager::removeAllActionsFromTarget(CCObject *pTarget)  
  210. {  
  211.     // 有效性判断  
  212.     if (pTarget == NULL)  
  213.     {  
  214.         return;  
  215.     }  
  216.     //定义一个哈希表项指针,并通过哈希表的查询宏取得对应项地址返回给指针。  
  217.     tHashElement *pElement = NULL;  
  218.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  219.     //如果找到此项  
  220.     if (pElement)  
  221.     {     
  222.         //如果此哈希表项有正在播放的动画并且这个动画并未被设为要回收。  
  223.         if (ccArrayContainsObject(pElement->actions, pElement->currentAction) && (! pElement->currentActionSalvaged))  
  224.         {  
  225.               //将当前正在播放的动画的引用计数器加1并设置其回收标记为true。引用计数加1的目的是人为使其暂不能被正常释放,需要待后面再减1后才可以被释放。  
  226.             pElement->currentAction->retain();  
  227.             pElement->currentActionSalvaged = true;  
  228.         }  
  229.          //清空当前哈希表项的动画集。  
  230.         ccArrayRemoveAllObjects(pElement->actions);  
  231.          //如果当前哈希表项正处于使用中,暂不释放,只将其要回收的标记设为true。  
  232.         if (m_pCurrentTarget == pElement)  
  233.         {  
  234.             m_bCurrentTargetSalvaged = true;  
  235.         }  
  236.         else  
  237.         {  
  238.               //释放当前哈希表项  
  239.             deleteHashElement(pElement);  
  240.         }  
  241.     }  
  242.     else  
  243.     {  
  244. //        CCLOG("cocos2d: removeAllActionsFromTarget: Target not found");  
  245.     }  
  246. }  
  247. //将指定动画从动画管理器中移除  
  248. void CCActionManager::removeAction(CCAction *pAction)  
  249. {  
  250.     //有效性判断  
  251.     if (pAction == NULL)  
  252.     {  
  253.         return;  
  254.     }  
  255.     //定义一个哈希表项指针,并通过哈希表的查询宏取得对应项地址返回给指针。  
  256.     tHashElement *pElement = NULL;  
  257.     CCObject *pTarget = pAction->getOriginalTarget();  
  258.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  259.     //如果找到此项  
  260.     if (pElement)  
  261.     {  
  262.          //取得pAction处于当前项的动画集的索引  
  263.         unsigned int i = ccArrayGetIndexOfObject(pElement->actions, pAction);  
  264.          //如果这个索引是有效的,调用函数将pElement的指定索引的动画移除。  
  265.         if (UINT_MAX != i)  
  266.         {  
  267.             removeActionAtIndex(i, pElement);  
  268.         }  
  269.     }  
  270.     else  
  271.     {  
  272.         CCLOG("cocos2d: removeAction: Target not found");  
  273.     }  
  274. }  
  275. //将指定演员的指定动画删除  
  276. void CCActionManager::removeActionByTag(unsigned int tag, CCObject *pTarget)  
  277. {  
  278.     //有效性判断  
  279.     CCAssert((int)tag != kCCActionTagInvalid, "");  
  280.     CCAssert(pTarget != NULL, "");  
  281.     //定义哈希表项指针变量,并通过哈希表处理宏取得相应哈希表项  
  282.     tHashElement *pElement = NULL;  
  283.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  284.     //如果能找到哈希表项  
  285.     if (pElement)  
  286.     {  
  287.         //取得哈希表项的动画集中的动画数量  
  288.         unsigned int limit = pElement->actions->num;  
  289.         //遍历动画集中的所有动画  
  290.         for (unsigned int i = 0; i < limit; ++i)  
  291.         {  
  292.             //取得每一项动画  
  293.             CCAction *pAction = (CCAction*)pElement->actions->arr[i];  
  294.             //查看是否是指定演员的指定动画。  
  295.             if (pAction->getTag() == (int)tag && pAction->getOriginalTarget() == pTarget)  
  296.             {  
  297.                   //如果是,则删除此项。  
  298.                 removeActionAtIndex(i, pElement);  
  299.                 break;  
  300.             }  
  301.         }  
  302.     }  
  303. }  
  304.   
  305. //取得指定演员的指定动画  
  306. CCAction* CCActionManager::getActionByTag(unsigned int tag, CCObject *pTarget)  
  307. {  
  308.     //有效性判断  
  309.     CCAssert((int)tag != kCCActionTagInvalid, "");  
  310.     //定义哈希表项指针变量,并通过哈希表处理宏取得相应哈希表项  
  311.     tHashElement *pElement = NULL;  
  312.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  313.     //如果能找到哈希表项  
  314.     if (pElement)  
  315.     {  
  316.          //如果此哈希表项的动画集不为空  
  317.         if (pElement->actions != NULL)  
  318.         {  
  319.             //取得哈希表项的动画集中的动画数量  
  320.             unsigned int limit = pElement->actions->num;  
  321.         //遍历动画集中的所有动画  
  322.   
  323.             for (unsigned int i = 0; i < limit; ++i)  
  324.             {  
  325.                 //取得每一项动画  
  326.                CCAction *pAction = (CCAction*)pElement->actions->arr[i];  
  327.                 //查看是否是指定动画。  
  328.                 if (pAction->getTag() == (int)tag)  
  329.                 {  
  330.                     return pAction;  
  331.                 }  
  332.             }  
  333.         }  
  334.         CCLOG("cocos2d : getActionByTag: Action not found");  
  335.     }  
  336.     else  
  337.     {      
  338.         // CCLOG("cocos2d : getActionByTag: Target not found");  
  339.     }  
  340.     //找不到要找的动画。返回NULL。  
  341.     return NULL;  
  342. }  
  343. //取得指定演员的动画集中的动画数量  
  344. unsigned int CCActionManager::numberOfRunningActionsInTarget(CCObject *pTarget)  
  345. {  
  346.   
  347.     //定义哈希表项指针变量,并通过哈希表处理宏取得相应哈希表项  
  348.     tHashElement *pElement = NULL;  
  349.     HASH_FIND_INT(m_pTargets, &pTarget, pElement);  
  350.     if (pElement)  
  351.     {  
  352.          //如果找到了,判断动画集是否为空,如果不为空返回动画数量,否则返回零。  
  353.         return pElement->actions ? pElement->actions->num : 0;  
  354.     }  
  355.   
  356.     return 0;  
  357. }  
  358.   
  359. //动画管理器的更新函数。  
  360. void CCActionManager::update(float dt)  
  361. {  
  362.     //遍历哈希表的所有项。  
  363.     for (tHashElement *elt = m_pTargets; elt != NULL; )  
  364.     {  
  365.          //将当前哈希表项保存到变量m_pCurrentTarget中。并将此项对应的回收标记m_bCurrentTargetSalvaged 设为false,  
  366.         m_pCurrentTarget = elt;  
  367.         m_bCurrentTargetSalvaged = false;  
  368.          //如果当前项的动画处于播放状态。  
  369.         if (! m_pCurrentTarget->paused)  
  370.         {  
  371.             //遍历当前项的动画集中的所有动画  
  372.             for (m_pCurrentTarget->actionIndex = 0; m_pCurrentTarget->actionIndex < m_pCurrentTarget->actions->num;  
  373.                 m_pCurrentTarget->actionIndex++)  
  374.             {  
  375.                   //取得遍历项的动画  
  376.                 m_pCurrentTarget->currentAction = (CCAction*)m_pCurrentTarget->actions->arr[m_pCurrentTarget->actionIndex];  
  377.                   //如果遍历项动画为空,跳过后遍历下一个动画。  
  378.                 if (m_pCurrentTarget->currentAction == NULL)  
  379.                 {  
  380.                     continue;  
  381.                 }  
  382.                   //设置回收标记为false。  
  383.                 m_pCurrentTarget->currentActionSalvaged = false;  
  384.                   //更新当前动画的播放  
  385.                 m_pCurrentTarget->currentAction->step(dt);  
  386.                   //如果当前项的回收标记为true,则进行释放处理。  
  387.                 if (m_pCurrentTarget->currentActionSalvaged)  
  388.                 {  
  389.                     m_pCurrentTarget->currentAction->release();  
  390.                 } else  
  391.                 if (m_pCurrentTarget->currentAction->isDone())  
  392.                 {   //如果当前动画处于结束状态,则停止动画  
  393.                     m_pCurrentTarget->currentAction->stop();  
  394.                        //为了在removeAction中正确释放动画,这里先创建一个临时变量pAction记录一下要释放的动画。  
  395.                     CCAction *pAction = m_pCurrentTarget->currentAction;  
  396.                     //在removeAction之前将当前哈希表项中的当前动画设为NULL,否则不能释放。  
  397.                     m_pCurrentTarget->currentAction = NULL;  
  398.                     removeAction(pAction);  
  399.                 }  
  400.   
  401.                 m_pCurrentTarget->currentAction = NULL;  
  402.             }  
  403.         }  
  404.   
  405.         //使for循环能够继续  
  406.         elt = (tHashElement*)(elt->hh.next);  
  407.   
  408.         // 如果当前哈希表项处于回收状态且其动画集为空,删除此哈希表项。  
  409.         if (m_bCurrentTargetSalvaged && m_pCurrentTarget->actions->num == 0)  
  410.         {  
  411.             deleteHashElement(m_pCurrentTarget);  
  412.         }  
  413.     }  
  414.   
  415.     // 将变量m_pCurrentTarge置空。  
  416.     m_pCurrentTarget = NULL;  
  417. }  
  418.   
  419. NS_CC_END  

     动画管理器的代码读完了,大概了解了它的功能,但它在哪里使用呢?我们可以打开显示设备管理器CCDirector类的头文件,在其中找到:

CC_PROPERTY(CCActionManager*,m_pActionManager, ActionManager);

并在CPP中搜索m_pActionManager:

 

  C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(145):    m_pActionManager = new CCActionManager();

 C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(146):   m_pScheduler->scheduleUpdateForTarget(m_pActionManager,kCCPrioritySystem, false);

  C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(175):    CC_SAFE_RELEASE(m_pActionManager);

 C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(887):    if (m_pActionManager != pActionManager)

 C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(890):        CC_SAFE_RELEASE(m_pActionManager);

 C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(891):        m_pActionManager = pActionManager;

 C:\cocos2d-2.0-x-2.0.2\cocos2dx\CCDirector.cpp(897):    return m_pActionManager;

 

    第一句在init函数中创建动画管理器。

    第二句在创建后将其加入系统更新函数要调用更新的对象。

    第三句在析构函数中释放动画管理器。

    第四,五,六句在setActionManager中更改动画管理器。

    第七句是取得动画管理器。

    这其中关键是第二句。因为有了它,所以动画管理器的update才会被调用。这样,我们在动画管理器的Update中加断点,启动程序,你可以发现中断并显示调用堆栈。

 

 

    流程是这样的: 在CCApplication的run函数中,显示设备链调用相应的场景显示函数drawScene来绘制场景,然后调用了CCScheduler的update函数,在这个函数里,对所有注册要调用update的对象指针进行遍历并调用其update函数,而CCActionManager的update会对所有演员的动作调用step函数,最终实现各个动画的播放。


    好了,我们现在呼吸一下,听我把这个背后的故事讲给大家。

 

    CCAction 是 动画基类,它派生出了很多可爱的动画类型,当你要让某个演员去表现一个动画的时候,你就对这个演员使用“runAction”来表演对应的动画。这个演员在收到你的指令后,它把自已的名字(其实是自已的指针)和这个动画一起告诉了显示部门长官—“设备管理器手下的成员之一  -- “动画管理器”,“动画管理器”这家伙在收到演员的需求后,就答应在每一次刷新时更新相应的动画。

 

    你懂了么?如果懂了?咱们就暂时休息一下。后面还有两斧子。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值