繼上一篇搭建主界面後,本篇著手構建遊戲核心的幀動畫系統。許多新人入職時動畫模塊已封裝完畢,導致不理解「幀」「動作」「動畫」的層級關係,遇到策劃需求「攻擊第 3 幀發射子彈」時一臉懵圈。因此我們拋棄 Cocos2d-x 內建 Animation,從零實現一套可控、可擴展的動畫系統。
| 術語 | 含義 | 例子 |
|---|---|---|
| Animation(動畫對象) | 可繪製的實體,如一個主角精靈 | 敵兵、防御塔、蘿卜 |
| Action(動作) | 一組有序幀的集合,非 Cocos2d-x 的 CCAction | 跑步、攻擊、待機、眨眼 |
| Frame(幀) | 動作的最小單位,對應一張紋理/切片 | 攻擊:抬刀(幀1)→揮刀(幀2)→收刀(幀3) |
關鍵洞察:同一類動畫的「動作-幀-紋理」元數據是共享的,不應隨每個實例重複存儲。因此引入 FrameAnimationBase(元數據)與 FrameAnimation(運行時實例)分離設計。
action_name → Vector 映射AddFrame(action, frameName)、GetFrame(action, index)defaultAction(首個添加的動作)base 指針、currentAction、currentFrameIndex、內部 CCSpritePlay(actionName):切換動作,重置幀索引為 0Step():推進到下一幀,循環播放,調用 sprite->setDisplayFrame()Step()class FrameAnimationBase : public CCObject {
friend class FrameAnimation;
CCDictionary* actionDic; // actionName -> CCArray
string defaultAction;
public:
static FrameAnimationBase* create();
void AddFrame(string actionName, CCSpriteFrame* frame);
void AddFrame(string actionName, string frameName); // 從緩存獲取 frame
CCSpriteFrame* GetFrame(string actionName, int index);
};
class FrameAnimation : public CCNode {
FrameAnimationBase* base;
string currAction;
int currFrameIndex;
CCSprite* sprite;
public:
static FrameAnimation* create(FrameAnimationBase* base);
void Play(string actionName); // 切換動作
void Step(); // 推進幀
};
void FrameAnimation::Step() {
CCArray* frames = base->GetFrames(currAction);
if (++currFrameIndex >= frames->count()) currFrameIndex = 0; // 循環
sprite->setDisplayFrame(base->GetFrame(currAction, currFrameIndex));
}
在 TestLayer 中構建:
base->AddFrame("run", "land_boss_pink01.png")…ani = FrameAnimation::create(base)ani->Step() 觀察幀切換luobo.xml 構建 Base,支持「happy/run/attack」多動作
FrameAnimationBase::createFromFile()AnimationManager:單例、資源緩存、全局定時器驅動 Step()原則:無需求不擴展。每個功能皆因具體遊戲需求而生,經版本迭代沉澱,而非憑空設計「通用大而全」組件。