帧动画的本质非常简单:在渲染每一帧时切换精灵的纹理贴图,依次播放一组预先加载好的图片,就构成了连续的动画效果。

下面是 Lite2D 中 Animation 类的实现。它继承自 Action,只能挂在 Sprite 上运行,支持设置每帧延迟、循环次数,以及播放结束后是否恢复到原始纹理。

Animation.h

#ifndef __ANIMATION__
                #define __ANIMATION__
                
                
                #include "Action.h"
                #include <vector>
                class Sprite;
                class Texture2D;
                
                
                
                /**
                 * @brief create a frame animation
                 * @warning this only runAction on a Sprite
                 */
                class DLL  Animation :public Action
                {
                public:
                	static Animation*create();
                	/**
                	 * @brief add a frame file
                	 */
                	void addFrameFile(const std::string file);
                	/**
                	 * @brief set delay time per frame
                	 */
                	void setPerFrameDelay(float delay);
                	/**
                	 * @brief  set loop times
                	 * @note default is 1
                	 */
                	void setLoops(int loop);
                
                
                	~Animation();
                
                
                	/**
                	 * @brief  set is show origin texture  when over
                	 */
                	void setOriginTexture(bool b);
                
                protected:
                
                	virtual void setTarget(Node*target)override;
                
                	void reset();
                
                
                	virtual void update()override;
                	Animation();
                	Sprite*_target;//target to run this action must is a Sprite
                	bool is_origin;//is show origin texture?
                	void clear();// clear
                	std::vector<Texture2D*> _queue;
                	int current_index; // current frame count
                
                	int loops = 0; // loops
                	int current_loop = 0;
                	Texture2D*_tex_origin;//
                
                
                };

Animation.cpp

#include"Animation.h"
                #include "Sprite.h"
                #include "../render/TextureCache.h"
                
                Animation::Animation() :
                loops(1),
                current_loop(0),
                current_index(0),
                is_origin(true)
                {
                	_is_init = true;
                
                }
                
                
                Animation*Animation::create()
                {
                	Animation *ins = new Animation;
                	ins->autorelease();
                	return ins;
                
                }
                
                void Animation::update()
                {
                
                	current += _speed;
                
                	if (current >= _total_time)
                	{//is time to show next frame
                
                		if (current_index > _queue.size() - 1)
                		{// is over this loop
                			//_isdone = true;
                			if (current_loop <= loops)
                			{// current_loop < loop then go on Animation
                				this->reset();
                				current_loop++;
                
                			}
                			else
                			{ // done
                				_isdone = true;
                				this->reset();
                				if (is_origin)
                				{
                					_target->setTexture2D(_tex_origin);
                				}
                				else
                				{
                					_tex_origin->release();
                				}
                				return;
                			}
                
                
                		}
                		else
                		{ // set next frame texture
                			_target->setTexture2D(_queue[current_index]);
                			current = 0;
                
                			++current_index;
                		}
                	}
                
                }
                
                void Animation::setTarget(Node*target)
                {
                	_target = (Sprite*)target;
                	_tex_origin = _target->getTexture2D();
                	_tex_origin->retain();
                
                }
                
                void Animation::addFrameFile(const std::string file)
                {
                
                	Texture2D* tex = TextureCache::getInstance()->getTexture2DByName(file);
                	tex->retain();
                
                	_queue.push_back(tex);
                
                }
                
                void Animation::setPerFrameDelay(float delay)
                {
                	_total_time = delay;
                
                }
                
                void Animation::setLoops(int loop)
                {
                	if (loop < 0)
                	{
                		this->loops = 0x7fffffff;//bug
                	}
                	else
                		this->loops = loop;
                
                
                }
                
                Animation::~Animation()
                {
                	this->clear();
                
                
                }
                
                void Animation::clear()
                {
                	for (const auto&tex : _queue)
                	{
                		tex->release();
                	}
                	_queue.clear();
                	_tex_origin->release();
                }
                
                void Animation::setOriginTexture(bool b)
                {
                	this->is_origin = b;
                }
                
                void Animation::reset()
                {
                	current = 0;
                	current_index = 0;
                }