这种序列帧动画要求每一帧的宽高必须一一致,否则动画播起来会出问题。
需要的图片类似图1.1 会把所有的动作拼接到一张图上,这样做也是为了节省内存和减少DrawCall,切换动作的时候只需要重新计算图片的UV,然后把算出来的UV作为新区域贴在原来的那张纹理面片上即可。
图1.1
Animate是Animation的一部分,一个Animation可以保存多个Animate,也可以理解成Animate只是一个动画片段,Animation是完整的动画控制器。这个结构其实有点像Unity的AnimateClip和Animator。
不多说,上代码,自己去看代码吧,实现不是很难,不多讲了。
程序1.1
Animate.h 完整代码
#pragma once
namespace U2D
{
enum MovementEvent
{
START,
COMPLETE,
};
class CAnimate :public CPicture
{
friend class CAnimation;
private:
char name[50]; //动画名
UINT frameWidth;//每一帧的宽度
UINT frameHeight;//每一帧的高度
UINT rows;//总行数
UINT cols;//总列数
UINT startIndex;//开始的索引编号
UINT endIndex;//结束的索引编号
UINT curIndex;//当前的索引编号
bool isPlaying;//是否播放
bool isLoop;//是否循环
UINT frameSpeed;//每一帧的速度
UINT frameTimer;//每一帧的时间
animate_selector listener_movementEvent; //动画事件监听
public:
CAnimate(char *fileName, UINT rows, UINT cols);
CAnimate(CCTexture *tex, UINT rows, UINT cols);
void setName(char *name) { strcpy(this->name, name); }
char *getName() { return this->name; }
void setFrameIndex(UINT startIndex, UINT endIndex)
{
this->startIndex = startIndex;
this->endIndex = endIndex;
curIndex = startIndex;
}
Vector2 getFrameSize() { return Vector2(frameWidth, frameHeight); }
UINT getFrameCount() { return endIndex - startIndex + 1; }
void play() { isPlaying = true; }
void stop() { isPlaying = false; }
void repeat(bool isLoop) { this->isLoop = isLoop; }
void setDelayUnit(UINT frameSpeed) { this->frameSpeed = frameSpeed; }
void setMovementEventCallFunc(animate_selector fun_movementEvent);//设置动画事件的回调函数
void draw();
void all_Anchor_0_0();
void all_Anchor_05_05();
public:
CAnimate() {}
~CAnimate(void) {}
};
}
程序1.2
Animate.cpp 完整代码
#include "Engine.h"
namespace U2D
{
CAnimate::CAnimate(char *fileName, UINT rows, UINT cols)
:CPicture(fileName)
{
strcmp(this->name, fileName);
this->rows = rows;
this->cols = cols;
isPlaying = true;
isLoop = true;
frameSpeed = 10;
frameWidth = pTexture->getWidth() / cols;
frameHeight = pTexture->getHeight() / rows;
startIndex = 0;
endIndex = rows*cols - 1;
curIndex = startIndex;
}
CAnimate::CAnimate(CCTexture *tex, UINT rows, UINT cols)
:CPicture(tex)
{
strcmp(this->name, tex->getName());
this->rows = rows;
this->cols = cols;
isPlaying = true;
isLoop = true;
frameSpeed = 10;
frameWidth = tex->getWidth() / cols;
frameHeight = tex->getHeight() / rows;
startIndex = 0;
endIndex = rows*cols - 1;
curIndex = startIndex;
}
void CAnimate::setMovementEventCallFunc(animate_selector fun_movementEvent)
{
this->listener_movementEvent = fun_movementEvent;
}
void CAnimate::draw()
{
if (isPlaying)
{
if (frameTimer++%frameSpeed == 0)
{
if (curIndex == startIndex)
{
if (listener_movementEvent)
{
if (parent != NULL)
{
(parent->*listener_movementEvent)(this, MovementEvent::START);
}
else
(parent->*listener_movementEvent)(this, MovementEvent::START);
}
}
if (curIndex == endIndex + 1)
{
if (isLoop)
{
curIndex = startIndex;
}
else
{
isPlaying = false;
curIndex = endIndex;
}
if (listener_movementEvent)
{
if (parent != NULL)
{
if (parent != NULL)
{
(parent->*listener_movementEvent)(this, MovementEvent::COMPLETE);
}
else
(parent->*listener_movementEvent)(this, MovementEvent::COMPLETE);
}
}
}
(&srcRect,
curIndex%cols*frameWidth,
curIndex / cols*frameHeight,
(curIndex%cols + 1)*frameWidth,
(curIndex / cols + 1)*frameHeight);
curIndex++;
}
}
CPicture::draw();
}
void CAnimate::all_Anchor_0_0()
{
}
void CAnimate::all_Anchor_05_05()
{
}
}
程序1.3
Animation.h 完整代码
#pragma once
namespace U2D {
class CAnimation :public CElement
{
friend class CPlayer;
protected:
list animateList; //动画的链表用名字判断,有就返回,没有就new一个
CAnimate *animate; //当前播放的动画
animation_selector listener_movementEvent; //动画集事件监听
void animateEvent(CAnimate* animate, MovementEvent type);
UINT rows;
UINT cols;
char*fileName;
public:
CAnimation();
CAnimate* addAnimate(char *animName, char *fileName, UINT rows, UINT cols);
CAnimate* addAnimate(char *animName, CCTexture *tex, UINT rows, UINT cols);
CAnimate* findAnimate(char *animName);
void setAnimate(char *animName);
Vector2 getFrameSize() { return animate->getFrameSize(); }
UINT getFrameCount() { return animate->getFrameCount(); }
void play() { animate->play(); }
void stop() { animate->stop(); }
void repeat(bool isLoop) { animate->repeat(isLoop); }
void setDelayUnit(UINT frameSpeed) { animate->setDelayUnit(frameSpeed); }
void setFrameIndex(UINT startIndex, UINT endIndex) { return animate->setFrameIndex(startIndex, endIndex); }
void setName_FrameIndex(char*name, UINT startIndex, UINT endIndex);
void setMovementEventCallFunc(animation_selector fun_movementEvent);
void draw();
void setCurrentAllanchor(float ox, float oy);
RECT getBoundBox();
~CAnimation();
};
}
程序1.4
Animation.cpp 完整代码
#include "Engine.h"
namespace U2D
{
CAnimation::CAnimation()
{
animate = NULL;
listener_movementEvent = NULL;
}
CAnimate* CAnimation::addAnimate(char *animName, char *fileName, UINT rows, UINT cols)
{
CAnimate* anim = findAnimate(animName);//查找这个动画名字,如果找不到就会返回空
if (anim != NULL) //如果不为空就说明找到了
return anim;
this->rows = rows;
this->cols = cols;
this->fileName = fileName;
anim = new CAnimate(fileName, rows, cols); //如果为空就new一个对象压进去。并且把名字设置好
anim->setName(animName); //设置动画名字
anim->setParent(this); //CAnimation是CNode的子类,子类拥有父类的所有数据,所以压入CAnimation就等同于压入了CNode。
anim->setMovementEventCallFunc(animate_selector(&CAnimation::animateEvent));//回调函数
animateList.push_back(anim); //压进链表
setAnimate(animName); //设置动画
return animateList.back(); //把刚压进去的对象返回出去
}
CAnimate* CAnimation::addAnimate(char *animName, CCTexture *tex, UINT rows, UINT cols)
{
CAnimate* anim = findAnimate(animName);
if (anim != NULL)
return anim;
this->rows = rows;
this->cols = cols;
anim = new CAnimate(tex, rows, cols);
anim->setName(animName);
anim->setParent(this);
anim->setMovementEventCallFunc(animate_selector(&CAnimation::animateEvent));
animateList.push_back(anim);
setAnimate(animName);
return animateList.back();
}
CAnimate* CAnimation::findAnimate(char *animName)
{
list::iterator iter;
for (iter = animateList.begin(); iter != animateList.end(); iter++)
{
if (strcmp((*iter)->name, animName) == 0)
{
return *iter;
}
}
return NULL;
}
void CAnimation::setAnimate(char *animName)
{
animate = findAnimate(animName);
animate->startIndex = animate->startIndex;//这个写的不对、明天去参考伟哥的写法
//animate->curIndex = animate->startIndex;
animate->isPlaying = true;
animate->frameTimer = 0;
}
void CAnimation::setName_FrameIndex(char*name, UINT startIndex, UINT endIndex)
{
CAnimate* anim = findAnimate(name);
anim = new CAnimate(fileName, rows, cols); //如果为空就new一个对象压进去。并且把名字设置好
anim->setName(name); //设置动画名字
anim->setParent(this); //CAnimation是CNode的子类,子类拥有父类的所有数据,所以压入CAnimation就等同于压入了CNode。
anim->setFrameIndex(startIndex, endIndex);
anim->frameTimer = 0;
animateList.push_back(anim); //压进链表
setAnimate(name); //设置动画
}
void CAnimation::draw()
{
Matrix3 scaleMatrix;
Matrix3 rotateMatrix;
Matrix3 transMatrix;
//放缩图片
Scale(scaleMatrix, scale.x, scale.y);
//水平翻转
if (flip == true)
scaleMatrix._11 *= -1;
//旋转图片
Rotate(rotateMatrix, angle);
// 平移图片到我们的指定位置
Translate(transMatrix, pos.x, pos.y);
local_matrix = scaleMatrix*rotateMatrix*transMatrix;
if (parent == NULL)
{
world_color = local_color;
world_matrix = local_matrix;
}
else
{
sColor col = parent->getWorldColor();
world_color.r = local_color.r*col.r;
world_color.g = local_color.g*col.g;
world_color.b = local_color.b*col.b;
world_color.a = local_color.a*col.a;
world_matrix = local_matrix*parent->getWorldMatrix();
}
if (visible == false)
return;
animate->draw();
}
void CAnimation::setCurrentAllanchor(float ox, float oy)
{
}
void CAnimation::setMovementEventCallFunc(animation_selector fun_movementEvent)
{
listener_movementEvent = fun_movementEvent;
}
void CAnimation::animateEvent(CAnimate* animate, MovementEvent type)
{
if (listener_movementEvent)
{
if (parent != NULL)
(parent->*listener_movementEvent)(this, type, animate->name);
else
(this->*listener_movementEvent)(this, type, animate->name);
}
}
RECT CAnimation::getBoundBox()
{
return animate->getBoundBox();
}
CAnimation::~CAnimation()
{
}
}
谢谢大家