接上一節內容:cocos2dx - v2.3.3編輯器簡單使用及不同分辨率適配
本節主要Cocos骨骼動畫的創建及使用
一、新建
用Cocos Studio工具新建一個狀態欄項目。如下圖:
當然也可以新建一個空的Cocos項目,然后在 文件->新建文件 中選擇骨骼動畫來創建新的骨骼動畫,如下圖
因為這里只講簡單用法,着重使用,所有直接創建英雄示例動畫。
二、添加動畫
選擇動畫模式,並點擊如下播放按鈕,可以看到現在默認的動畫。
示例中只有ALL動畫,我們需要將每個動畫按起始結束幀率分開,添加如下動畫:
這樣就有了休閑動畫(default),跑步動畫(run),攻擊動畫(attack),受傷動畫(injure),死亡動畫(death)。
這里還是額外在講下骨骼動畫記錄的使用。
1、首先如下在右邊的幀查看中 添加起始幀
2、直接改變預覽顯示中的骨骼對應的位置或者,旋轉等,這時編輯器就會自動記錄當前幀的各自狀態。
3、在間隔一定的幀率再添加對應的結束幀,然后設置坐標等。這樣在起始結束幀就可以對應的播放動畫了。
注意事項:
默認情況下,新添加的幀只會記錄以下左圖幾個數據,如果我們需要記錄類似顯示隱藏,透明度等數據,需要在調整數據前將右圖的開始記錄動畫選項勾上。
這樣就會對修改的其他數據進行記錄了,如下圖
三、導出到項目
同樣的,在編輯好動畫之后,我們需要跟上一節一樣導出到游戲項目的Resource目錄下
為了方便管理,我們這里也把玩家單獨提出一個類來。

#ifndef __CPlayer_H__ #define __CPlayer_H__ #include "cocos2d.h" #include "cocostudio/CocoStudio.h" USING_NS_CC; using namespace cocostudio::timeline; enum enAction { ACT_NONE, // 無 ACT_DEFAULT, // 待機 ACT_RUN, // 跑步 ACT_ATTACK, // 攻擊 ACT_INJURE, // 受傷 ACT_DEATH, // 死亡 }; class CPlayer : public Node { public: // implement the "static create()" method manually CREATE_FUNC(CPlayer); virtual bool init(); void Move(float deltaX); void Reset(); void Attack(); private: void PlayAction(enAction nAction); CPlayer(); ~CPlayer(); Node* m_pNode; enAction m_nActType; ActionTimeline* m_pAction; }; #endif __CPlayer_H__ #include "Player.h" CPlayer::CPlayer() :m_pNode(NULL), m_pAction(NULL), m_nActType(ACT_NONE) { } CPlayer::~CPlayer() { m_pNode = NULL; if (m_pAction) { m_pAction->release(); m_pAction = NULL; } } bool CPlayer::init() { std::string filePath = "Hero.csb"; m_pNode = CSLoader::createNode(filePath); if (m_pNode) { m_pAction = CSLoader::createTimeline(filePath); if (m_pAction) { m_pAction->retain(); m_pNode->runAction(m_pAction); PlayAction(enAction::ACT_DEFAULT); } this->addChild(m_pNode); return true; } return false; } void CPlayer::Move(float deltaX) { if (m_nActType != ACT_DEFAULT && m_nActType != ACT_RUN) { return; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); #define isFloatZero(a) ((a) > -0.000001f && (a) < 0.0000001f) if (!isFloatZero(deltaX)) { float delta = deltaX<0 ? -2 : 2; // 計算移動后的位置 float desX = this->getPositionX() + delta; if (desX<origin.x) { desX = origin.x; } if (desX>origin.x + visibleSize.width) { desX = origin.x + visibleSize.width; } this->setScaleX(deltaX<0 ? -1 : 1); this->setPositionX(desX); } PlayAction(ACT_RUN); } void CPlayer::Attack() { PlayAction(ACT_ATTACK); } void CPlayer::Reset() { PlayAction(enAction::ACT_DEFAULT); } void CPlayer::PlayAction(enAction nAction) { if (m_pAction) { if (m_nActType == nAction || m_nActType == ACT_ATTACK) { return; } m_nActType = nAction; switch (nAction) { case ACT_DEFAULT: m_pAction->play("default",true); break; case ACT_RUN: m_pAction->play("run", true); break; case ACT_ATTACK: { m_pAction->play("attack", false); std::function<void()> func = [this](){ m_pAction->play("default", true); m_nActType = ACT_DEFAULT; }; m_pAction->setLastFrameCallFunc(func); } break; case ACT_INJURE: m_pAction->play("injure", false); break; case ACT_DEATH: m_pAction->play("death", false); break; default: break; } } }
這樣在戰斗中,添加了對應的頭文件后,我們就可以正常添加使用了。
// 加載玩家實體 m_pPlayer = CPlayer::create(); // 設置位置 m_pPlayer->setPosition(Vec2(visibleSize.width / 2 + origin.x, 80 + origin.y)); // 添加到節點上 this->addChild(m_pPlayer, 1);
然后在點擊屏幕的事件我們也做下修改。
bool HelloWorld::onTouchBegan(Touch *pTouch, Event *unused_event) { if (m_pPlayer) { // 防止超出屏幕 Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); if (pTouch->getLocation().x>visibleSize.width*0.5 + origin.x) { m_pPlayer->Attack(); } else { m_pPlayer->Move(pTouch->getDelta().x); } } return true; } void HelloWorld::onTouchMoved(Touch *pTouch, Event *pEvent) { if (m_pPlayer) { // 點擊左半屏幕 Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); if (pTouch->getLocation().x < visibleSize.width*0.5 + origin.x) { m_pPlayer->Move(pTouch->getDelta().x); } } } void HelloWorld::onTouchEnded(Touch *pTouch, Event *pEvent) { if (m_pPlayer) { m_pPlayer->Reset(); } }
這樣就實現了點擊左半屏移動,右半屏實現攻擊。效果如下