cocos2d-x动作原理

前端之家收集整理的这篇文章主要介绍了cocos2d-x动作原理前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

首先CCAction是所有动作的基类,如下图继承关系:

那么来看看CCAction的定义:

  1. class CC_DLL CCAction : public CCObject
  2. {
  3. public:
  4. CCAction(void);
  5. virtual ~CCAction(void);
  6. const char* description();
  7. virtual CCObject* copyWithZone(CCZone *pZone);
  8. //! return true if the action has finished
  9. virtual bool isDone(void);
  10. virtual void startWithTarget(CCNode *pTarget);
  11. /**
  12. called after the action has finished. It will set the 'target' to nil.
  13. IMPORTANT: You should never call "[action stop]" manually. Instead,use: "target->stopAction(action);"
  14. */
  15. virtual void stop(void);
  16. //! called every frame with it's delta time. DON'T override unless you know what you are doing.
  17. virtual void step(float dt);
  18. virtual void update(float time);
  19. inline CCNode* getTarget(void) { return m_pTarget; }
  20. inline void setTarget(CCNode *pTarget) { m_pTarget = pTarget; }
  21. inline CCNode* getOriginalTarget(void) { return m_pOriginalTarget; }
  22. inline void setOriginalTarget(CCNode *pOriginalTarget) { m_pOriginalTarget = pOriginalTarget; }
  23. inline int getTag(void) { return m_nTag; }
  24. inline void setTag(int nTag) { m_nTag = nTag; }
  25. public:
  26. static CCAction* create();
  27. protected:
  28. CCNode *m_pOriginalTarget;
  29. CCNode *m_pTarget;
  30. int m_nTag;
  31. };

在类定义最后有三个成员变量,而继承自CCAction的CCFiniteTimeAction主要新增加了一个用于保存该动作总完成时间的成员变量float m_fDuration;

对于其两个子类CCActionInstant和CCActionInterval,前者没有新增任何函数和变量,而后者增加了两个成员变量:float m_elapsed(记录从动作开始起逝去的时间);和bool m_bFirstTick(一个控制变量);

那么动作是如何执行的呢?

当一个节点调用runAction方法时,动作管理类CCActionManager(单例类)会将新的动作和节点添加到其管理的动作表中。

  1. CCAction * CCNode::runAction(CCAction* action)
  2. {
  3. CCAssert( action != NULL,"Argument must be non-nil");
  4. m_pActionManager->addAction(action,this,!m_bRunning);
  5. return action;
  6. }


在addAction中,将动作添加到动作队列后,就会对该动作调用其成员函数startWithTarget(CCNode* pTarget)来绑定该动作的执行节点,和初始化动作类的成员变量。

这些工作都完成后,每一帧刷新屏幕时,系统就会在CCActionManager中遍历动作表中的每一个动作,并调用动作的step(float)方法。而step方法主要负责计算m_elapsed的值,并调用update(float)方法

  1. void CCActionInterval::step(float dt)
  2. {
  3. if (m_bFirstTick)
  4. {
  5. m_bFirstTick = false;
  6. m_elapsed = 0;
  7. }
  8. else
  9. {
  10. m_elapsed += dt;
  11. }
  12. this->update(MAX (0,// needed for rewind. elapsed could be negative
  13. MIN(1,m_elapsed / MAX(m_fDuration,FLT_EPSILON) // division by 0
  14. )
  15. )
  16. );
  17. }

传入update方法的float型参数表示逝去的时间与动作完成需要的时间的比值,介于0-1之间,即动作完成的百分比。然后在update方法中,通过完成比例对节点的属性进行操作来达到动作的效果
例如:对MoveBy调用update时,通过传入的比例调用setPosition直接修改节点的属性

最后在每一帧结束后,CCActionManager的update会检查动作队列中每个动作的isDone函数是否返回true,如果返回true,则动作结束,将其从队列中删除

——————————————————————————————————————————————————————————————————————————

从上面知道:动作都是由CCActionManager来管理。那我们再来看看CCActionManager的工作原理。

在CCDirector初始化时,执行了如下代码

  1. // scheduler
  2. m_pScheduler = new CCScheduler();
  3. // action manager
  4. m_pActionManager = new CCActionManager();
  5. m_pScheduler->scheduleUpdateForTarget(m_pActionManager,kCCPrioritySystem,false);

可见动作管理类在创建时就注册了Update定时器,那么CCScheduler在游戏的每一帧mainLoop更新中都会触发CCActionManager注册的update(float )方法。调度器原理请参照此链接http://www.cnblogs.com/songcf/p/3162414.html

  1. // main loop
  2. void CCActionManager::update(float dt)
  3. {
  4. //枚举动作表中的每一个节点
  5. for (tHashElement *elt = m_pTargets; elt != NULL; )
  6. {
  7. m_pCurrentTarget = elt;
  8. m_bCurrentTargetSalvaged = false;
  9. if (! m_pCurrentTarget->paused)
  10. {
  11. //枚举节点的每一个动作 actions数组可能会在循环中被修改
  12. for (m_pCurrentTarget->actionIndex = 0; m_pCurrentTarget->actionIndex < m_pCurrentTarget->actions->num;
  13. m_pCurrentTarget->actionIndex++)
  14. {
  15. m_pCurrentTarget->currentAction = (CCAction*)m_pCurrentTarget->actions->arr[m_pCurrentTarget->actionIndex];
  16. if (m_pCurrentTarget->currentAction == NULL)
  17. {
  18. continue;
  19. }
  20. m_pCurrentTarget->currentActionSalvaged = false;
  21. m_pCurrentTarget->currentAction->step(dt);
  22. if (m_pCurrentTarget->currentActionSalvaged)
  23. {
  24. // The currentAction told the node to remove it. To prevent the action from
  25. // accidentally deallocating itself before finishing its step,we retained
  26. // it. Now that step is done,it's safe to release it.
  27. m_pCurrentTarget->currentAction->release();
  28. } else
  29. if (m_pCurrentTarget->currentAction->isDone())
  30. {
  31. m_pCurrentTarget->currentAction->stop();
  32. CCAction *pAction = m_pCurrentTarget->currentAction;
  33. // Make currentAction nil to prevent removeAction from salvaging it.
  34. m_pCurrentTarget->currentAction = NULL;
  35. removeAction(pAction);
  36. }
  37. m_pCurrentTarget->currentAction = NULL;
  38. }
  39. }
  40. // elt,at this moment,is still valid
  41. // so it is safe to ask this here (issue #490)
  42. elt = (tHashElement*)(elt->hh.next);
  43. // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
  44. if (m_bCurrentTargetSalvaged && m_pCurrentTarget->actions->num == 0)
  45. {
  46. deleteHashElement(m_pCurrentTarget);
  47. }
  48. }
  49. // issue #635
  50. m_pCurrentTarget = NULL;
  51. }

猜你在找的Cocos2d-x相关文章