cocos2dx

接上一节内容: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;
        } 
    }
}
View Code

这样在战斗中,添加了对应的头文件后,我们就可以正常添加使用了。

    // 加载玩家实体
    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();
    }
}

这样就实现了点击左半屏移动,右半屏实现攻击。效果如下

原文地址:https://www.cnblogs.com/stratrail/p/5038485.html