cocos2d-x中的动作分析

在cocos2d-x中动作的执行调度是受cocos2d-x的全局定时器控制的,当初始完导演后便已经启动用于管理动作的update定时器。

bool CCDirector::init(void)
{
	...
    m_pActionManager = new CCActionManager();
    m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);
    ...

    return true;
}
也就说主循环每帧都会调用这个定时器的调度,且优先级是小于0的,是一个高优先级的定时器。从上一篇文章可以得到的一个结果是当执行这个定时器调度时,由于是update的定时器,所以直接是每帧的调用m_pActionManager的update方法。

所以先看下这个动作管理器的定义:

//动作管理类
class CC_DLL CCActionManager : public CCObject
{
public:
    /**
     *  @js ctor
     */
	//构造
    CCActionManager(void);
    /**
     *  @js NA
     *  @lua NA
     */
    //析构
    ~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);

    /** Removes all actions from all the targets.
    */
    //从管理器中移除所有动作
    void removeAllActions(void);

    /** Removes all actions from a certain target.
     All the actions that belongs to the target will be removed.
     */
    //从管理器中移除节点的所有动作
    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);

    /** Gets an action given its tag an a target
     @return the Action the with the given tag
     */
    //从管理器中获取一个带有指定标记的动作
    CCAction* getActionByTag(unsigned int tag, CCObject *pTarget);

    /** Returns the numbers of actions that are running in a certain target. 
     * Composable actions are counted as 1 action. Example:
     * - If you are running 1 Sequence of 7 actions, it will return 1.
     * - If you are running 7 Sequences of 2 actions, it will return 7.
     */
    //返回指定节点中正在运行的动作的数量
    unsigned int numberOfRunningActionsInTarget(CCObject *pTarget);

    /** Pauses the target: all running actions and newly added actions will be paused.
    */
    //暂停节点的动作
    void pauseTarget(CCObject *pTarget);

    /** Resumes the target. All queued actions will be resumed.
    */
    //恢复节点的动作
    void resumeTarget(CCObject *pTarget);
    
    /** Pauses all running actions, returning a list of targets whose actions were paused.
     */
    //暂停所有正在运行的动作,并返回这些动作的集合
    CCSet* pauseAllRunningActions();
    
    /** Resume a set of targets (convenience function to reverse a pauseAllRunningActions call)
     */
    //恢复集合中指定的动作
    void resumeTargets(CCSet *targetsToResume);

protected:
    // declared in CCActionManager.m
    //根据索引移除
    void removeActionAtIndex(unsigned int uIndex, struct _hashElement *pElement);
    //删除哈希表中指定的项
    void deleteHashElement(struct _hashElement *pElement);
    //为动作申请内存空间
    void actionAllocWithHashElement(struct _hashElement *pElement);
    //更新,由主循环的update定时器调用更新
    void update(float dt);

protected:
    struct _hashElement    *m_pTargets;//存储目标节点的哈希表
    struct _hashElement    *m_pCurrentTarget;//当前的节点的哈希元素
    bool            m_bCurrentTargetSalvaged;//可回收标记
};

从上面的注释可以看出它的功能就是将动作加到自己的管理器中进行管理,当动作执行完后便会把这个动作从管理器中移除掉,另外还定义了两个哈希表来管理多个节点和执行节点和一个辅助的回收标记变量,跟定时器是设计十分相像:

typedef struct _hashElement
{
    struct _ccArray             *actions;//动作数组,即一个节点可以允许有多个动作
    CCObject                    *target;//执行动作的目标节点
    unsigned int                actionIndex;//索引
    CCAction                    *currentAction;//当前正在执行的动作
    bool                        currentActionSalvaged;//当前正在执行的动作是否被标记为可回收
    bool                        paused;//是否暂停
    UT_hash_handle                hh;//操作哈希表的句柄
} tHashElement;
整个实现细节如下(最终要的便是update是每帧都会被主循环所调用):‘

CCActionManager::CCActionManager(void)
: m_pTargets(NULL), 
  m_pCurrentTarget(NULL),
  m_bCurrentTargetSalvaged(false)
{

}

CCActionManager::~CCActionManager(void)
{
    CCLOGINFO("cocos2d: deallocing %p", this);

    removeAllActions();//移除多有的动作
}

// private

void CCActionManager::deleteHashElement(tHashElement *pElement)
{
    ccArrayFree(pElement->actions);//释放资源
    HASH_DEL(m_pTargets, pElement);//从哈希表中删除元素
    pElement->target->release();//动作目标的引用计数减1
    free(pElement);//释放哈希元素
}

void CCActionManager::actionAllocWithHashElement(tHashElement *pElement)
{
    // 4 actions per Node by default
    if (pElement->actions == NULL)//每个节点初始化可存放4个节点
    {
        pElement->actions = ccArrayNew(4);
    }else 
    if (pElement->actions->num == pElement->actions->max)//如果节点的动作数量大于当前的已拥有的动作数量
    {
        ccArrayDoubleCapacity(pElement->actions);//将容量扩大2倍
    }

}

void CCActionManager::removeActionAtIndex(unsigned int uIndex, tHashElement *pElement)
{
    CCAction *pAction = (CCAction*)pElement->actions->arr[uIndex];

    if (pAction == pElement->currentAction && (! pElement->currentActionSalvaged))//如果待移除的动作与当前正在执行的动作相等且没有被标记可回收,那么将其标记可回收
    {
        pElement->currentAction->retain();//引用计数加1,保证当前的动作能完整的被执行完
        pElement->currentActionSalvaged = true;//标记为可回收该动作
    }

    ccArrayRemoveObjectAtIndex(pElement->actions, uIndex, true);//将该动作从动作管理器中移除掉

    // update actionIndex in case we are in tick. looping over the actions
    if (pElement->actionIndex >= uIndex)//保证动作被移除时循环能被正确执行
    {
        pElement->actionIndex--;
    }

    if (pElement->actions->num == 0)//如果节点的没有动作列表
    {
        if (m_pCurrentTarget == pElement)//如果待移除的动作与当前正在执行的动作相等
        {
            m_bCurrentTargetSalvaged = true;//将该正在执行的动作标记为可回收
        }
        else
        {//不相等
            deleteHashElement(pElement);//直接从哈希表中移除掉
        }
    }
}

// pause / resume

void CCActionManager::pauseTarget(CCObject *pTarget)
{
    tHashElement *pElement = NULL;
    HASH_FIND_INT(m_pTargets, &pTarget, pElement);//在哈希表中查找该节点的哈希项
    if (pElement)//找到,设置暂停
    {
        pElement->paused = true;
    }
}

void CCActionManager::resumeTarget(CCObject *pTarget)
{
    tHashElement *pElement = NULL;
    HASH_FIND_INT(m_pTargets, &pTarget, pElement);//在哈希表中查找该节点的哈希项
    if (pElement)//找到,恢复运行
    {
        pElement->paused = false;
    }
}

CCSet* CCActionManager::pauseAllRunningActions()
{
    CCSet *idsWithActions = new CCSet();//创建一个收集即将被设置为暂停的集合
    idsWithActions->autorelease();//放到内存回收池
    
    for (tHashElement *element=m_pTargets; element != NULL; element = (tHashElement *)element->hh.next) //遍历动作管理器
    {
        if (! element->paused) //如果不是暂停状态
        {
            element->paused = true;//设置暂停
            idsWithActions->addObject(element->target);//加到集合中
        }
    }    
    //返回集合
    return idsWithActions;
}

void CCActionManager::resumeTargets(cocos2d::CCSet *targetsToResume)
{    
    CCSetIterator iter;
    for (iter = targetsToResume->begin(); iter != targetsToResume->end(); ++iter)//遍历集合中的动作
    {
        resumeTarget(*iter);//恢复动作
    }
}

// run

void CCActionManager::addAction(CCAction *pAction, CCNode *pTarget, bool paused)
{
	//参数检查
    CCAssert(pAction != NULL, "");
    CCAssert(pTarget != NULL, "");

    tHashElement *pElement = NULL;
    // we should convert it to CCObject*, because we save it as CCObject*
    CCObject *tmp = pTarget;
    HASH_FIND_INT(m_pTargets, &tmp, pElement);//在哈希表中查找该节点的哈希项
    if (! pElement)//没找到
    {
    	//创建一个新的哈希项
        pElement = (tHashElement*)calloc(sizeof(*pElement), 1);
        pElement->paused = paused;//设置暂停
        pTarget->retain();//引用计数加1
        pElement->target = pTarget;//设置目标节点
        HASH_ADD_INT(m_pTargets, target, pElement);//将新创建的哈希项放到哈希表中
    }
    //为哈希项申请存放内存空间
     actionAllocWithHashElement(pElement);
 
     CCAssert(! ccArrayContainsObject(pElement->actions, pAction), "");
     ccArrayAppendObject(pElement->actions, pAction);//加到动作管理器中
     //初始化执行目标节点
     pAction->startWithTarget(pTarget);
}

// remove

void CCActionManager::removeAllActions(void)
{
    for (tHashElement *pElement = m_pTargets; pElement != NULL; )//遍历动作管理器中的所有动作
    {
        CCObject *pTarget = pElement->target;//执行动作的目标节点
        pElement = (tHashElement*)pElement->hh.next;//下一个元素
        removeAllActionsFromTarget(pTarget);//将该目标节点从动作管理器中移除掉
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值