从零开始学习cocoStudio(5)--骨骼动画使用方法

骨骼动画


      当前有两种模型动画的方式:顶点动画和骨骼动画。顶点动画中,每帧动画其实就是模型特定姿态的一个“快照”。通过在帧之间插值的方法,引擎可以得到平滑的动画效果。在骨骼动画中,模型具有互相连接的“骨骼”组成的骨架结构,通过改变骨骼的朝向和位置来为模型生成动画。

      骨骼动画比顶点动画要求更高的处理器性能,但同时它也具有更多的优点,骨骼动画可以更容易、更快捷地创建。不同的骨骼动画可以被结合到一起——比如,模型可以转动头部、射击并且同时也在走路。一些引擎可以实时操纵单个骨骼,这样就可以和环境更加准确地进行交互——模型可以俯身并向某个方向观察或射击,或者从地上的某个地方捡起一个东西。多数引擎支持顶点动画,但不是所有的引擎都支持骨骼动画。

      一些引擎包含面部动画系统,这种系统使用通过音位(phoneme)和情绪修改面部骨骼集合来表达面部表情和嘴部动作。

      有关cocoStdio制作骨骼动画,可以参考下用户手册Cocos2d-x 3.0开发(六)使用cocoStudio创建一个骨骼动画。本篇博文只是讲解怎么在cocos2d-x使用骨骼动画的。


骨骼动画使用




实现代码:


角色类:Player.h

#ifndef __CowboyScene__Player__
#define __CowboyScene__Player__

#include <iostream>

#include "cocos2d.h"
#include "cocos-ext.h"

USING_NS_CC;
USING_NS_CC_EXT;
using namespace gui;

#define WALK_SPEED 1
#define WALK_LEFT 1
#define WALK_RIGHT -1

enum PlayerState
{
    IDLE = 0,      //默认
    WALK,          //行走
    SHOOT,         //射击
    GRENADE        //子弹
};

class Player:public CCObject
{
public:
    Player(CCNode* node);
    void update(float dt);              //更新角色状态
    void updateAnimation();             //状态判断及播放动画
    void updateMovement();              //行走状态
    void play(std::string animName);    //播放动画
    bool isLockState();                 //锁定角色状态
    
    inline void setState(PlayerState state) {newState = state;} //设置角色状态
    void setDirection(int newDirection); //设置方向

private:
    CCNode* playerNode;
    CCArmatureAnimation* animation;     //动画变量
    PlayerState currentState;           //当前状态
    PlayerState newState;               //更换状态
    int direction;                      //方向
    bool lockState;                     //锁定状态
    void onAnimationEvent(CCArmature *pArmature, MovementEventType eventType, const char *animationID);                   //角色射击状态
};



#endif /* defined(__CowboyScene__Player__) */
角色类:Player.cpp

#include "Player.h"

Player::Player(CCNode* playerNode):CCObject()
{
    CCComRender *pRender = static_cast<CCComRender*>(playerNode->getChildByTag(10004)->getComponent("CCArmature"));
    
    this->playerNode = playerNode->getChildByTag(10004);
    
    CCArmature* animationNode = static_cast<CCArmature*>(pRender->getNode());
    
    this->animation = animationNode->getAnimation();
    this->animation->setMovementEventCallFunc(this, movementEvent_selector(Player::onAnimationEvent));
    currentState = IDLE;
    newState = IDLE;
    lockState = false;
}

//设置方向
void Player::setDirection(int newDirection)
{
    direction = newDirection;
    playerNode->setScaleX(direction * fabs(playerNode->getScaleX()));
}

void Player::update(float dt)
{
    if (currentState == newState || isLockState())
    {
        updateMovement();
    }
    else
    {
        currentState = newState;
        updateAnimation();
    }
}

void Player::updateMovement()
{
    CCPoint oldPos = playerNode->getPosition();
    if (currentState == WALK)
    {
        playerNode->setPosition(oldPos.x + -direction * WALK_SPEED,oldPos.y);
    }
}

void Player::updateAnimation()
{
    switch (currentState)
    {
        case IDLE:
            animation->play("stand");
            break;
        case SHOOT:
            animation->play("stand_fire");
            break;
        case WALK:
            animation->play("walk");
            break;
        case GRENADE:
            animation->play("grenade");
            lockState = true;
            break;
        default:
            break;
    }
}

bool Player::isLockState()
{
    return lockState;
}

void Player::onAnimationEvent(cocos2d::extension::CCArmature *pArmature, cocos2d::extension::MovementEventType eventType, const char *animationID)
{
    if (eventType == LOOP_COMPLETE) {
        if (strcmp(animationID, "grenade") == 0)
        {
            lockState = false;
            newState = IDLE;
        }
    }
}

导入骨骼动画及使用:

HelloWorldScene.cpp

bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

    /
    // 2. add a menu item with "X" image, which is clicked to quit the program
    //    you may modify it.

    // add a "close" icon to exit the progress. it's an autorelease object
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback));
    
	pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
                                origin.y + pCloseItem->getContentSize().height/2));

    // create menu, it's an autorelease object
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition(CCPointZero);
    this->addChild(pMenu, 1);
    
    //创建场景
    CCNode* gameScene = SceneReader::sharedSceneReader()->createNodeWithSceneFile("DemoCowboy.json");
    addChild(gameScene);

    //创建角色
    CCNode* playerNode = gameScene;
    player = new Player(playerNode);

    //创建按钮(控制左、右、射击)
    CCComRender *pRender = static_cast<CCComRender*>(playerNode->getChildByTag(10005)->getComponent("GUIComponent"));
    UILayer* ui = static_cast<UILayer*>(pRender->getNode());
    
    UIButton * btnLeft = (UIButton*)ui->getWidgetByName("LeftButton");
    btnLeft->addTouchEventListener(this, toucheventselector(HelloWorld::onMoveLeft));
    
    UIButton* btnRight = (UIButton*)ui->getWidgetByName("RightButton");
    btnRight->addTouchEventListener(this, toucheventselector(HelloWorld::onMoveRight));
    
    UIButton* btnFire = (UIButton*)ui->getWidgetByName("FireButton");
    //    btnFire->addReleaseEvent(this, coco_releaseselector(HelloWorld::onFire));
    btnFire->addTouchEventListener(this, toucheventselector(HelloWorld::onFire));
    
    //Enable update loop
    this->scheduleUpdate();
    
    return true;
}
更新事件及按钮触发事件

void HelloWorld::update(float dt)
{
    player->update(dt);
}

void HelloWorld::onMoveLeft(cocos2d::CCObject *pSender, TouchEventType type)
{
    if (type == TOUCH_EVENT_BEGAN)
    {
        player->setDirection(WALK_LEFT);
        player->setState(WALK);
    }
    if (type == TOUCH_EVENT_ENDED)
    {
        player->setState(IDLE);
    }
}

void HelloWorld::onMoveRight(cocos2d::CCObject *pSender, TouchEventType type)
{
    if (type == TOUCH_EVENT_BEGAN)
    {
        player->setDirection(WALK_RIGHT);
        player->setState(WALK);
    }
    if (type == TOUCH_EVENT_ENDED)
    {
        player->setState(IDLE);
    }
}

void HelloWorld::onFire(cocos2d::CCObject *pSender, TouchEventType type)
{
    if (type == TOUCH_EVENT_BEGAN)
    {
        player->setState(SHOOT);
    }
    if (type == TOUCH_EVENT_ENDED)
    {
        player->setState(IDLE);
    }
}
示例资源及代码:   https://github.com/chukong/CocoStudioSamples 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热血枫叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值