您的位置:首页 > 移动开发 > Cocos引擎

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

2014-01-21 09:46 417 查看

骨骼动画

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

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

      一些引擎包含面部动画系统,这种系统使用通过音位(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 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  cocos2d-x cocostudio