导入动画 spine
spine 是一款2d动画制作工具,具体介绍见:http://zh.esotericsoftware.com/
我们让我们的引擎支持它制作的动画。
首先从github下载官方runTimes,这里选择spine-c。
然后我们要处理的是它的渲染与创建。
/********************************************************************
Copyright(C), 2012-2013,
FileName:SkeletonAnimation.h
Description:
Author:cloud
Created:2014/11/07
history:
7:11:2014 15:41 by
*********************************************************************/
#pragma once
#include "export/Node.h"
#include "spine/spine.h"
#include "base/GLFix.h"
#include "base/render/Quad.h"
namespace cloud
{
class SkeletonAnimation :public Node
{
public:
SkeletonAnimation(const char* atasPath,const char* jsonPath);
~SkeletonAnimation();
void initialize(const char* atasPath,const char* jsonPath);
void update(float dt);
void createTexture(const char* texturePath);
void removeTexture();
void render(const Mat4& parentMat4);
Size getTextureSize();
void playAnimation(const char* animationName,bool isLoop);
void stopAnimation(int endTrackIdx = -1);
protected:
std::string _animationName;
spAnimationState* _state;
spSkeleton* _skeleton;
GLuint _textureID;
Size _textureSize;
std::string _texturePath;
QuadCommand _quadCommand;
Quad* _quads;
BlendFunc _blendFunc;
int _totalQuads;
};
}
/********************************************************************
Copyright(C), 2012-2013,
FileName:SkeletonAnimation.cpp
Description:
Author:cloud
Created:2014/11/07
history:
7:11:2014 15:42 by
*********************************************************************/
#include "base/TextureManager.h"
#include "spine/SkeletonAnimation.h"
#include "base/render/Renderer.h"
#include "base/EngineLog.h"
//TODO:未加入事件回调
namespace cloud
{
SkeletonAnimation::SkeletonAnimation(const char* atasPath,const char* jsonPath):_skeleton(NULL),_state(NULL),_quads(NULL),_totalQuads(0)
{
_blendFunc = BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::string dirPath = atasPath;
int pos = dirPath.rfind("/");
if (pos > -1)
{
dirPath = dirPath.substr(0,pos+1);
}
else
{
dirPath = "";
}
initialize(atasPath,jsonPath);
_totalQuads = _skeleton->slotsCount;
_quads = (Quad*)malloc( _totalQuads * sizeof(Quad));
memset(_quads, 0, _totalQuads * sizeof(Quad));
}
SkeletonAnimation::~SkeletonAnimation()
{
if (_quads)
{
free(_quads);
}
spAnimationState_dispose(_state);
spSkeleton_dispose(_skeleton);
}
void SkeletonAnimation::initialize(const char* atasPath,const char* jsonPath)
{
spAtlas* atlas = spAtlas_createFromFile(atasPath,this);
spSkeletonJson* json = spSkeletonJson_create(atlas);
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, jsonPath);
spSkeletonJson_dispose(json);
_skeleton = spSkeleton_create(skeletonData);
_state = spAnimationState_create(spAnimationStateData_create(_skeleton->data));
}
void SkeletonAnimation::playAnimation(const char* animationName,bool isLoop)
{
_animationName = animationName;
spAnimationState_setAnimationByName(_state, 0, animationName, isLoop);
if(!isScheduleUpdate())
scheduleUpdate();
}
void SkeletonAnimation::stopAnimation(int endTrackIdx)
{
if(isScheduleUpdate())
unscheduleUpdate();
if (endTrackIdx != -1)
{
spAnimationState_setAnimationByName(_state, endTrackIdx, _animationName.c_str(), false);
}
}
void SkeletonAnimation::update(float dt)
{
//spBone* rootBone = _skeleton->bones[0];
spSkeleton_update(_skeleton,dt);
spAnimationState_update(_state, dt);
spAnimationState_apply(_state, _skeleton);
spSkeleton_updateWorldTransform(_skeleton);
}
void SkeletonAnimation::createTexture(const char* texturePath)
{
int textureWidth;
int textureHeight;
_textureID = TextureManager::getInstance()->createTexture(texturePath,textureWidth,textureHeight);
_textureSize = Size(textureWidth,textureHeight);
_contentSize = _textureSize;
_texturePath = texturePath;
}
void SkeletonAnimation::removeTexture()
{
TextureManager::getInstance()->removeTexture(_texturePath.c_str());
_texturePath = "";
}
void SkeletonAnimation::render(const Mat4& parentMat4)
{
//
float vertices[8];
for (int i = 0, n = _skeleton->slotsCount; i < n; i++)
{
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue;
spRegionAttachment* regionAttachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(regionAttachment, slot->bone, vertices);
float r = slot->r;
float g = slot->g;
float b = slot->b;
float a =slot->a;
Quad* quad = _quads+ i;
quad->bl._color.r = r;
quad->bl._color.g = g;
quad->bl._color.b = b;
quad->bl._color.a = a;
quad->tl._color.r = r;
quad->tl._color.g = g;
quad->tl._color.b = b;
quad->tl._color.a = a;
quad->tr._color.r = r;
quad->tr._color.g = g;
quad->tr._color.b = b;
quad->tr._color.a = a;
quad->br._color.r = r;
quad->br._color.g = g;
quad->br._color.b = b;
quad->br._color.a = a;
quad->bl._position.x = vertices[SP_VERTEX_X1];
quad->bl._position.y = vertices[SP_VERTEX_Y1];
quad->tl._position.x = vertices[SP_VERTEX_X2];
quad->tl._position.y = vertices[SP_VERTEX_Y2];
quad->tr._position.x = vertices[SP_VERTEX_X3];
quad->tr._position.y = vertices[SP_VERTEX_Y3];
quad->br._position.x = vertices[SP_VERTEX_X4];
quad->br._position.y = vertices[SP_VERTEX_Y4];
quad->bl._texCoord.x = regionAttachment->uvs[SP_VERTEX_X1];
quad->bl._texCoord.y = regionAttachment->uvs[SP_VERTEX_Y1];
quad->tl._texCoord.x = regionAttachment->uvs[SP_VERTEX_X2];
quad->tl._texCoord.y = regionAttachment->uvs[SP_VERTEX_Y2];
quad->tr._texCoord.x = regionAttachment->uvs[SP_VERTEX_X3];
quad->tr._texCoord.y = regionAttachment->uvs[SP_VERTEX_Y3];
quad->br._texCoord.x = regionAttachment->uvs[SP_VERTEX_X4];
quad->br._texCoord.y = regionAttachment->uvs[SP_VERTEX_Y4];
}
_quadCommand.init(_quads,_textureID,_totalQuads,_blendFunc,this->transform(parentMat4));
Renderer::getInstance()->addQuadCommand(&_quadCommand);
}
Size SkeletonAnimation::getTextureSize()
{
return _textureSize;
}
}
还要实例化它的三个函数:
#include "extension.h"
#include "base/fileUtils/FileUtils.h"
#include "SkeletonAnimation.h"
void _spAtlasPage_createTexture (spAtlasPage* self, const char* path)
{
cloud::SkeletonAnimation* skeletonAnimation = (cloud::SkeletonAnimation*) self->atlas->rendererObject;
if(skeletonAnimation)
{
skeletonAnimation->createTexture(path);
self->width = skeletonAnimation->getTextureSize().width;
self->height = skeletonAnimation->getTextureSize().height;
}
}
void _spAtlasPage_disposeTexture (spAtlasPage* self)
{
cloud::SkeletonAnimation* skeletonAnimation = (cloud::SkeletonAnimation*) self->atlas->rendererObject;
if(skeletonAnimation)
skeletonAnimation->removeTexture();
}
char* _spUtil_readFile (const char* path, int* length)
{
unsigned char* outData = NULL;
unsigned int outLen = 0;
cloud::FileUtils::getInstance()->readFile(path,&outData,outLen);
*length = outLen;
return (char*)outData;
}
调用代码如下:
SkeletonAnimation* ske = new SkeletonAnimation("spineboy.atlas","spineboy.json");
ske->setScale(0.3f);
ske->setPosition(Point(winSize.width* 0.5,winSize.height * 0.3));
ske->playAnimation("walk",true);
addChild(ske,3);
要注意的几点是:
_spAtlasPage_createTexture里要被纹理的长宽,重新赋值回去。
spin的纹理为png,而且默认是上下颠倒了的。