接上一节内容:cocos2dx - v2.3.3编辑器简单使用及不同分辨率适配
本节主要Cocos骨骼动画的创建及使用
一、新建
用Cocos Studio工具新建一个状态栏项目。如下图:
当然也可以新建一个空的Cocos项目,然后在 文件->新建文件 中选择骨骼动画来创建新的骨骼动画,如下图
因为这里只讲简单用法,着重使用,所有直接创建英雄示例动画。
二、添加动画
选择动画模式,并点击如下播放按钮,可以看到现在默认的动画。
示例中只有ALL动画,我们需要将每个动画按起始结束帧率分开,添加如下动画:
这样就有了休闲动画(default),跑步动画(run),攻击动画(attack),受伤动画(injure),死亡动画(death)。
这里还是额外在讲下骨骼动画记录的使用。
1、首先如下在右边的帧查看中 添加起始帧
2、直接改变预览显示中的骨骼对应的位置或者,旋转等,这时编辑器就会自动记录当前帧的各自状态。
3、在间隔一定的帧率再添加对应的结束帧,然后设置坐标等。这样在起始结束帧就可以对应的播放动画了。
注意事项:
默认情况下,新添加的帧只会记录以下左图几个数据,如果我们需要记录类似显示隐藏,透明度等数据,需要在调整数据前将右图的开始记录动画选项勾上。
这样就会对修改的其他数据进行记录了,如下图
三、导出到项目
同样的,在编辑好动画之后,我们需要跟上一节一样导出到游戏项目的Resource目录下
为了方便管理,我们这里也把玩家单独提出一个类来。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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(); } }
这样就实现了点击左半屏移动,右半屏实现攻击。效果如下