这种序列帧动画要求每一帧的宽高必须一一致,否则动画播起来会出问题。
需要的图片类似图1.1 会把所有的动作拼接到一张图上,这样做也是为了节省内存和减少DrawCall,切换动作的时候只需要重新计算图片的UV,然后把算出来的UV作为新区域贴在原来的那张纹理面片上即可。
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<CAnimate*> 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<CAnimate*>::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() { } }
谢谢大家