7.游戏引擎中2D序列帧动画控制器的实现

        这种序列帧动画要求每一帧的宽高必须一一致,否则动画播起来会出问题。

        需要的图片类似图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<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()
	{
	}

}

谢谢大家

猜你喜欢

转载自blog.csdn.net/qq_33531923/article/details/126824114
今日推荐