twixed.ru huh… nothing interesting here

15Июн/110

Создание класса анимации объектов на ActionScript 3. P.1

В этой статье я опишу создание простейшего класса, позволяющего выполнять элементарную анимацию объектов во Flash на ActionScript 3. Я знаю, что Adobe придумали такую клевую вещь как Motion Tween, которая позволяет легко выполнять перемещения и трансформации графических объектов, но так как я использую FlashDevelop для разработки Flash-приложений, сей чудный инструмент мне не доступен. Существуют, конечно, способы подключения необходимых классов к проекту, но танцевать с бубном мне не хотелось, к тому же были необходимы лишь простейщие эффекты анимации, как то: перемещенеи объекта по осям x и y и плавное изменение прозрачности для создания эффектов постепенного появления/исчезновения объектов. Поэтому, недолго думая, я приступил к создания собственного класса анимации, который удовлетворил бы моим нуждам. Заранее предупрежу, что я не претендую на звание профессионала по программированию на ActionScript, поэтому код наверняка будет не идеальным. Прошу отнестись с пониманием. Итак, приступим...

Первым делом, мы создадим новый проект:

В только что созданный проект добавим новый класс и назовем его Animate:

На этом с картинками заканчиваем, и переходим непосредственно к коду. Только что созданный класс будет выглядеть вот так:

package  
{
	/**
	 * ...
	 * @author twix
	 */
	public class Animate 
	{
 
		public function Animate() 
		{
 
		}
 
	}
 
}

Первое, с чем нам надо определиться - с параметрами, которые будут передаваться в конструктор класса. Предположим, при создании, он будет получать ссылку на объект, с которым необходимо произвести некоторые манипуляции, их характер и силу, продолжительность и callback-функцию, выполняемую по завершении анимации. Для этого добавляем их в параметры конструктора и получаем следующее:

public function Animate(target:DisplayObject, animationType:String = "none", timeOut:Number = 100, callback:Function = null)

Перечислим их:
target:DisplayObject - мы не знаем о типе объекта, на который получаем ссылку, поэтому предполагаем, что это может быть вообще любой графический объект;
animationType:String = "none" - тип анимации. Ключевой параметр, который может принимать разные значения, например "fadeIn" или "x=100";
timeOut:Number = 100 - количество миллисекунд, за которое анимация должна быть выполнена;
callback:Function = null - функция обратного вызова, которая будет вызываться после завершения анимации, может быть не задана.

Естественно, нам потребуются переменные, для хранения этих параметров и использования их в других функциях класса. Их мы поместим в самое начало его описания:

private var _target:*;		// ссылка на объект, который является "жертвой" анимации
private var _animate:String;	// тип анимации
private var _callback:Function;	// ссылка на функцию обратного вызова
private var _start:uint = 0;	// количество миллисекунд, прошедших с запуска Flash на момент старта анимации
private var _interval:uint;	// указатель на таймер, взводимый вызовом функции setInterval
private var _timeOut:Number;	// заданное время анимации в миллисекундах

Конструктор должен присвоить этим переменным необходимые значения, а затем запустить таймер, который будет вызывать основную функцию-обработчик каждую миллисекунду, поэтому добавляем в него следующие строки:

if (target != null) // анимация будет работать только в том случае, если передана ссылка на объект
{
	_target = target;		// запоминаем переданную ссылку на объект
	_animate = animationType;	// то же делаем с типом анимации
	_callback = callback;		// и с функцией обратного вызова
	_timeOut = timeOut;		// и со временем действия анимации
	_start = flash.utils.getTimer();	// сохраняем время, в которое началась анимация
	_interval = flash.utils.setInterval(doAnimation, 1); // запускаем таймер, который будет вызывать функцию doAnimation каждую миллисекунду
}

Теперь опишем главную функцию нашего класса - doAnimation. Из ее названия понятно, что она должна делать. На данный момент, для примера, разберем простейший вариант с плавным появлением и исчезновением обьекта - fadeIn и fadeOut.

private function doAnimation():void
{
	var percent:Number = (getTimer() - _start) / _timeOut; // вычисляем количество уже затраченного времени
	switch(_animate)
	{
		case "fadeIn":				// если тип анимации - плавное появление
			flash.display.DisplayObject(_target).alpha = percent;
			break;
		case "fadeOut":				// если тип анимации - плавное исчезновение
			flash.display.DisplayObject(_target).alpha = 1 - percent;
			break;
	}
	if (percent >= 1)				// если весь временной путь пройден
	{
		clearInterval(_interval);		// отключаем таймер
		if (_callback != null) _callback();	// и вызываем функцию обратного вызова, если она задана
	}
}

Теперь, чтобы проверить, что все идет по плану, мы вернемся к классу Main нашего проекта и добавим следующие строки в его функцию init():

var sprite:Sprite = new Sprite();	// создаем новый графический объект
sprite.graphics.beginFill(0x0000FF);
sprite.graphics.drawRect(0, 0, 50, 50); // рисуем на нем синий квадрат со стороной 50 пикселей
sprite.graphics.endFill();
sprite.x = sprite.y = 100;		// указываем его положение
addChild(sprite);			// и добавляем на сцену
new Animate(sprite, "fadeIn", 500);	// выполняем анимацию - плавное появление

Запустив проект на сборку и выполнение, мы должны будем увидеть плавно появляющийся синий квадрат:

Я думаю, вы могли заметить, что анимация выполняется не слишком плавно. Это связано с тормозным поведением самого Flash. Несмотря на то, что таймер класса Animate должен вызывать функцию doAnimate() раз в 1 миллисекунду, он делает это значительно реже. По наблюдениям на моем компьютере, это происходит раз в 15-20 миллисекунд. На комьютерах с другой конфигурацией эта цифра будет варьировать. Поэтому, при использовании большого количества графических объектов в проекте, их анимация на слабых компьютерах может выполняться не так плавно, как хотелось бы. Но, увы, с этим придется мириться.

На данном этапе наш класс может предоставить два способа анимации объектов: плавное появление и плавное исчезновение. Чтобы не перегружать статью, я оставлю другие способы анимации (перемещение объекта по осям x и y) для следующей статьи. А сейчас просто приведу исходные коды двух файлов, задействованных в нашем проекте.

Main.as

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import Animate;
 
	/**
	 * ...
	 * @author twix
	 */
	public class Main extends Sprite 
	{
 
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			var sprite:Sprite = new Sprite();	// создаем новый графический объект
			sprite.graphics.beginFill(0x0000FF);
			sprite.graphics.drawRect(0, 0, 50, 50); // рисуем на нем синий квадрат со стороной 50 пикселей
			sprite.graphics.endFill();
			sprite.x = sprite.y = 100;		// указываем его положение
			addChild(sprite);			// и добавляем на сцену
			new Animate(sprite, "fadeIn", 500);	// выполняем анимацию - плавное появление
		}
 
	}
 
}

Animate.as

package  
{
	import flash.display.DisplayObject;
	import flash.utils.clearInterval;
	import flash.utils.getTimer;
	import flash.utils.setInterval;
	/**
	 * ...
	 * @author twix
	 */
	public class Animate 
	{
		private var _target:*;		// ссылка на объект, который является "жертвой" анимации
		private var _animate:String;	// тип анимации
		private var _callback:Function;	// ссылка на функцию обратного вызова
		private var _start:uint = 0;	// количество миллисекунд, прошедших с запуска Flash на момент старта анимации
		private var _interval:uint;	// указатель на таймер, взводимый вызовом функции setInterval
		private var _timeOut:Number;	// заданное время анимации в миллисекундах
 
		public function Animate(target:DisplayObject, animationType:String = "none", timeOut:Number = 100, callback:Function = null) 
		{
			if (target != null) // анимация будет работать только в том случае, если передана ссылка на объект
			{
				_target = target;		// запоминаем переданную ссылку на объект
				_animate = animationType;	// то же делаем с типом анимации
				_callback = callback;		// и с функцией обратного вызова
				_timeOut = timeOut;		// и со временем действия анимации
				_start = getTimer();		// сохраняем время, в которое началась анимация
				_interval = setInterval(doAnimation, 1); // запускаем таймер, который будет вызывать функцию doAnimation каждую миллисекунду
			}
		}
 
		private function doAnimation():void
		{
			var percent:Number = (getTimer() - _start) / _timeOut; // вычисляем количество уже затраченного времени
			switch(_animate)
			{
				case "fadeIn":				// если тип анимации - плавное появление
					DisplayObject(_target).alpha = percent;
					break;
				case "fadeOut":				// если тип анимации - плавное исчезновение
					DisplayObject(_target).alpha = 1 - percent;
					break;
			}
			if (percent >= 1)				// если весь временной путь пройден
			{
				clearInterval(_interval);		// отключаем таймер
				if (_callback != null) _callback();	// и вызываем функцию обратного вызова, если она задана
			}
		}
 
	}
 
}

Post to Twitter Post to Digg Post to Facebook Post to Google Buzz Send Gmail Post to LinkedIn

Комментарии (0) Пинги (0)

Пока нет комментариев.


Leave a comment

(required)

Нет обратных ссылок на эту запись.