在瞭解了CCAction
、CCFiniteTimeAction
和CCActionInterval
的類結構後,下面我們以它們爲例分析Cocos2d-x的動作機制。
當我們對CCNode
調用runAction(CCAction*
action)
方法時,動作管理類CCActionManager
(它是一個單例對象)會將新的CCAction
和對應的目標節點添加到其管理的動作表中。
在CCActionManager
的addAction
方法中,我們將動作添加到動作隊列之後,就會對該CCAction
調用成員函數startWithTarget(CCNode*
pTarget)
來綁定該動作的執行者。而在CCAction
的子類中(如CCActionInterval
),還初始化了一些參數:
void CCActionInterval::startWithTarget(CCNode *pTarget)
{
CCFiniteTimeAction::startWithTarget(pTarget);
m_elapsed = 0.0f;
m_bFirstTick = true;
}
當這些準備工作都完成後,每一幀刷新屏幕時,系統都會在CCActionManager
中遍歷其動作表中的每一個動作,並調用該動作的step(ccTimedt)
方法。step
方法主要負責計算m_elapsed
的值,並調用update(float
time)
方法,相關代碼如下:
void CCActionInterval::step(float dt)
{
if (m_bFirstTick)
{
m_bFirstTick = false;
m_elapsed = 0;
}
else
{
m_elapsed += dt;
}
this->update(MAX (0,
MIN(1, m_elapsed / MAX(m_fDuration, FLT_EPSILON))
)
);
}
傳入update
方法的time
參數表示逝去的時間與動作完成需要的時間的比值,是介於0和1之間的一個數,即動作完成的百分比。
CCActionInterval
並沒有進一步實現update
方法。下面我們繼續以繼承自CCActionInterval
的CCRotateTo
動作的update
方法爲例,分析update
函數是如何實現的,其實現代碼如下:
void CCRotateTo::update(float time)
{
if (m_pTarget)
{
m_pTarget->setRotation(m_fStartAngle + m_fDiffAngle * time);
}
}
看到這裏,我們已經能看出Cocos2d-x的動作機制的整個工作流程了。在CCRotateTo
中,最終完成的操作是修改目標節點的Rotation
屬性值,更新該目標節點的旋轉屬性值。
最後,在每一幀刷新結束後,在CCActionManager
類的update
方法中都會檢查動作隊列中每一個動作的isDone
函數是否返回true
。如果返回true
,則動作已完成,將其從隊列中刪除。isDone
函數的代碼如下:
bool CCActionInterval::isDone(void)
{
return m_elapsed >= m_fDuration;
}
對於不同的動作類,雖然整體流程大致都是先調用step
方法,然後按照各個動作的具體定義來更新目標節點的屬性,但是不同動作的具體實現會有所不同。例如,CCRepeatForever
動作的isDone
函數始終返回false
,因爲它是永遠在執行的動作;又如CCActionInstant
及其子類的step
函數中,向update
傳遞的參數值始終是1,因爲瞬時動作會在下一幀刷新後完成,不需要多次執行update
。