Skip to content
Vitalii Nikolenko edited this page Aug 22, 2018 · 5 revisions

Tweens

Inbetweening или tweening (твининг) это процесс создания промежуточных кадров между двумя изображениями который создаёт впечатление плавного превращения одного изображения в другое. Твины это рисунку между ключевыми кадрами которые помогают создать иллюзию движения. Твининг это ключевой процесс для всех типов анимации, включая компьютерную анимацию.

Oxygine предоставляет простой но мощный интерфейс твининга основанный на шаблонных классах. Он поддерживает твининг различных свойств (размер, поворот, положение и т.д.) и позволяет сцеплять твины и действия для создания сложных последовательностей.

Создание и добавление

у класса Actor есть метод addTween:

template<class Prop>
spTween addTween(const Prop &prop, timeMS duration, int loops = 1, bool twoSides = false, timeMS delay = 0, Tween::EASE ease = Tween::ease_linear)
  • duration длительность анимации в миллисекундах
  • loops количество повторов анимации. Значение -1 означает что анимация будет повторяться бесконечно.
  • Если twoSides установлено в true, тогда анимация будет происходить туда и обратно: от A к B, а затем опять к A.
  • delay задержка перед началом анимации в миллисекундах
  • ease Функция плавности которая контролирует ускорение анимации

в examples/Demo->Tweens есть примеры всех функций EASE.

Пример создания Tween, который передвинет спрайт в точку (400, 300) за 500 миллисекунд:

int duration = 500;//ms
spTween tween = sprite->addTween(Actor::TweenPosition(400, 300), duration);

Альтернативный метода addTween, который использует простой класс TweenOptions:

spTween tween = sprite->addTween(Actor::TweenAlpha(0), TweenOptions(duration).delay(100).loops(3));

В Oxygine есть большое количество уже созданных Tween для разных свойств.

Все Tweens добавленные в Actor исполняются одновременно и параллельно. Одновременно можно добавить несколько разных Tween. Если нужна последовательность из нескольких анимаций, то используйте класс TweenQueue.

Чтобы поймать момент окончания анимации можно использовать Tween::setDoneCallback метод. Пример использования:

void SomeClass::onTweenDone(Event *event)
{
	logs::messageln("tween done"); 
}


tween->setDoneCallback(CLOSURE(this, &SomeClass::onTweenDone));

Или подпишитесь на событие окончания TweenEvent::Done:

tween->addEventListener(TweenEvent::DONE, CLOSURE(this, &SomeClass::onTweenDone));

это работает несколько медленнее, чем setDoneCallback, т.к при первом вызове addEventListener происходит дополнительное выделение памяти.

Если необходимо удалить (отсоеденить от родителя) актера по окончанию анимации можно воспользоваться методом Tween::setDetachActor

tween->detachWhenDone();

Удаление

Для удаления уже добавленных Tween в Actor есть метод:

void Actor::removeTween(spTween);

Удаление по имени, где имя устанавливается с помощью метода Tween::setName:

void Actor::removeTweensByName(const std::string &name);

Если быть точным, то имя устанавливается через Object::setName, от которого унаследован Tween

Удаление всех Tween:

void Actor::removeTweens(bool callComplete = false);

если callComplete == false, то все Tween будут не просто удалены, но и завершены, с вызовом TweenEvent::DONE событий.

Спрайтовая анимация

Пример создания спрайтовой по кадровой анимации:

ResAnim* resAnim = resources.getResAnim("run"); 
spTween tween = sprite->addTween(TweenAnim(resAnim), duration);

Где анимация 'run' объявлена в xml файле с ресурсами:

<image file="run.png" cols = "7" />

В данном случае анимация 'run' состоит из 7 кадров.

Dummy Tween

Иногда в актера нужно добавить твин, который ничего не делает:

spTween tween = sprite->addTween(TweenDummy(), duration);

Но зато таким образом можно, например, удалить актера через duration миллисекунд:

tween->detachWhenDone();

Или вызвать произвольный callback по завершению:

tween->setDoneCallback(...);

TweenQueue

TweenQueue это наследник от класса Tween. TweenQueue используется для проигрывания анимаций последовательно.

Пример:

spTweenQueue tween = new TweenQueue;
tween->add(Actor::TweenX(100), 500);
tween->add(Actor::TweenY(100), 250);
tween->add(Actor::TweenAlpha(0), 300);
sprite->addTween(tween);

Более короткий способ:

sprite->addTween(TweenQueue::create(
	createTween(Actor::TweenX(100), 500),
	createTween(Actor::TweenY(100), 500),
	createTween(tween->add(Actor::TweenAlpha(0), 300)),
));

TweenQueue::create поддерживает до 5ти аргументов

Создание собственных Твинов

В Oxygine можно легко создавать и добавлять свои собственные Tween. Рассмотрим парочку уже существующих:

typedef Property<float, float, Actor, &Actor::getX, &Actor::setX>										TweenX;
typedef Property<float, float, Actor, &Actor::getY, &Actor::setY>										TweenY;
typedef Property<float, float, Actor, &Actor::getWidth, &Actor::setWidth>								TweenWidth;
typedef Property<float, float, Actor, &Actor::getHeight, &Actor::setHeight>								TweenHeight;
typedef Property<float, float, Actor, &Actor::getRotation, &Actor::setRotation>							TweenRotation;
typedef Property<unsigned char, unsigned char, Actor, &Actor::getAlpha, &Actor::setAlpha>				TweenAlpha;

Они создаются с помощью шаблонного класса Property, который использует уже существующие в актере методы Get и Set.

По этому же принципу можно создавать свои произвольные Tween для любого вашего актера:

class MySprite: public Sprite
{
public:
	float getMyValue() const;
	void  setMyValue(float v);
};

typedef Property<float, float, MySprite, &MySprite::getMyValue, &Actor::setMyValue>			MyValueTween;

mysprite->addTween(MyValueTween(123), 1000);

Произвольные Tween можно создавать и без шаблонного класса Property, в качестве примера можете посмотреть TweenAnim.

Создание собственных Твинов II

Существует другой, более продвинутый способ по созданию своего собственного Tween. В отличии от предыдущего примера он не использует шаблонный класс Property, а реализует весь Tween полностью.

В качестве примера реализуем MyTweenAnim для анимирования спрайта. MyTweenAnim будет похож на уже существующий TweenAnim, но в отличии от TweenAnim интервал из проигрываемых кадров, будет задаваться отдельно в xml файле с ресурсами (на основе произвольных атрибутов):

Обычная анимация в xml описывается так:

<image file="ninja.png" />

Но мы добавим к ней пару произвольный атрибутов frames-run и frames-attack, которые будут означать, что с 0 по 10 кадр расположена анимация бега, а с 11 по 20 анимация атаки:

<image file="ninja" frames-run="0-10" frames-attack="11-20" />

В каждом Tween должны быть реализованы методы init, update и объявлен 'type' Актера, с которым будет работать Tween:

class MyTweenAnim
{
public:
	typedef Sprite type;

	MyTweenAnim(const ResAnim *rs, const char *name) :_resAnim(rs), _start(0), _end(0)
	{
		char str[255];
		safe_sprintf(str, "frames-%s", name);
		const char *data = rs->getAttribute(str).as_string(0);
		if (data)
			sscanf(data, "%d-%d", &_start, &_end);
	}


	void init(Sprite &actor){}
	void update(Sprite &actor, float p, const UpdateState &us)
	{
		int frame = interpolate<int>(_start, _end, p);
		actor.setAnimFrame(_resAnim->getFrame(frame));	
	}

private:
	const ResAnim *_resAnim;
	int _start;
	int _end;
};

Пример использования:

spSprite sprite = new Sprite;
const ResAnim *rs = resources.getResAnim("ninja");
sprite->addTween(MyTweenAnim(rs, "run"), 1000);
Clone this wiki locally