twixed.ru huh… nothing interesting here

16Июн/110

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

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

Для начала прикинем, как мы будем выполнять анимацию перемещения по одной из осей на заданное расстояние. Это простейший вариант - так как в основной функции класса Animate вычисляется процент пройденного времени (от 0 до 1), положение объекта получается простым умножением этого числа на указанное расстояние. Таким образом при каждом вызове функции doAnimation мы будем иметь возможность точно узнать, где должен находиться объект в данный момент времени. С перемещением по осям к указанному значению технология немного отличается - путь, который объект должен будет пройти, нам не известен - его придется вычислить, отталкиваясь от значений текущего положения объекта и его положения на конец анимации.

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

private var _startPoint:Number;		// начальное положение объекта на оси
private var _delta:Number = 0;		// длина пути, который необходимо пройти объекту

Кажется, этого достаточно. Но было бы неплохо определиться и с описанием видов анимации, которые будут реализовываться в нашем классе. Как мы помним, они передаются конструктору в виде строки вторым параметром (мы уже используем "fadeIn" и "fadeOut"). Но как же передать еще и цифровое значение, обозначающее путь объекта или его конечную точку? Очень просто:
"x-100" - перемещение объекта по оси x на -100 пикселей;
"y+50" - перемещение объекта по оси y на 50 пикселей;
"y=30" - перемещение объекта по оси y с текущей позиции до 30.
Просто, не правда ли? Нам останется лишь обработать эту строку, выделив из нее цифровое значение, и записать его в переменную _delta.

if ( (_animate.substr(0, 1) == "x") )						// если указана анимация перемещения по оси x
	_startPoint = DisplayObject(_target).x;					// запоминаем стартовую позицию на оси x
if ( (_animate.substr(0, 1) == "y") )						// если указана анимация перемещения по оси y
	_startPoint = DisplayObject(_target).y;					// запоминаем стартовую позицию на оси y
if ( !isNaN(_startPoint) )							// проверяем, выполняется ли перемещение по наличию значения стартовой позиции
{
	switch(_animate.substr(1, 1))						//проверяем тип анимации перемещения
	{
		case "=":							// перемещение в указанную точку по оси
			_delta = parseInt(_animate.substr(2)) - _startPoint;	// вычисляем путь до указанной точки
			break;
		default:							// перемещение на указанное значение по оси
			_delta = parseInt(_animate.substr(1));			// здесь просто преобразуем часть строки в число и сохраняем его
	}
	_animate = _animate.substr(0, 1);					// запоминаем только тип анимации, обрезав числовое значение
}

Поместив эти строки в конструктор перед стартом таймера, мы будем иметь информацию, необходимую для выполнения перемещений объекта по осям. Само перемещение выполняется так же просто, как и изменение прозрачности объекта для типов анимации fadeIn и fadeOut:

case "x":					// если тип анимации - перемещение по оси x
	DisplayObject(_target).x = _startPoint + _delta * percent;
	break;
case "y":					// если тип анмиации - перемещение по оси y
	DisplayObject(_target).y = _startPoint + _delta * percent;
	break;

Теперь, если мы попробуем создать в модуле Main объект Animate с параметром анимации "x+100" или "y=200", то получим желаемый результат - перемещение синего квадрата по сцене. Однако, учитывая специфику работы таймера, может оказаться, что объект по завершении анимации оказывается чуть дальше нужной позиции. Происходит это потому, что к моменту последнего срабатывания прошло больше времени, чем мы отвели под анимацию, и переменная percent в функции doAnimation будет иметь значение больше единицы. Чтобы избежать этого, ограничим ее значение сверху, выполняя простую проверку сразу после вычисления значения переменной percent:

if (percent > 1) percent = 1;	// чтобы не "промахнуться", ограничиваем значение сверху

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

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;	// заданное время анимации в миллисекундах
		private var _startPoint:Number;	// начальное положение объекта на оси
		private var _delta:Number = 0;	// длина пути, который необходимо пройти объекту
 
		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();		// сохраняем время, в которое началась анимация
				if ( (_animate.substr(0, 1) == "x") )						// если указана анимация перемещения по оси x
					_startPoint = DisplayObject(_target).x;					// запоминаем стартовую позицию на оси x
				if ( (_animate.substr(0, 1) == "y") )						// если указана анимация перемещения по оси y
					_startPoint = DisplayObject(_target).y;					// запоминаем стартовую позицию на оси y
				if ( !isNaN(_startPoint) )							// проверяем, выполняется ли перемещение по наличию значения стартовой позиции
				{
					switch(_animate.substr(1, 1))						//проверяем тип анимации перемещения
					{
						case "=":							// перемещение в указанную точку по оси
							_delta = parseInt(_animate.substr(2)) - _startPoint;	// вычисляем путь до указанной точки
							break;
						default:							// перемещение на указанное значение по оси
							_delta = parseInt(_animate.substr(1));			// здесь просто преобразуем часть строки в число и сохраняем его
					}
					_animate = _animate.substr(0, 1);					// запоминаем только тип анимации, обрезав числовое значение
				}
				_interval = setInterval(doAnimation, 1); // запускаем таймер, который будет вызывать функцию doAnimation каждую миллисекунду
			}
		}
 
		private function doAnimation():void
		{
			var percent:Number = (getTimer() - _start) / _timeOut; // вычисляем количество уже затраченного времени
			if (percent > 1) percent = 1;	// чтобы не "промахнуться", ограничиваем значение сверху
			switch(_animate)
			{
				case "fadeIn":		// если тип анимации - плавное появление
					DisplayObject(_target).alpha = percent;
					break;
				case "fadeOut":		// если тип анимации - плавное исчезновение
					DisplayObject(_target).alpha = 1 - percent;
					break;
				case "x":		// если тип анимации - перемещение по оси x
					DisplayObject(_target).x = _startPoint + _delta * percent;
					break;
				case "y":		// если тип анмиации - перемещение по оси y
					DisplayObject(_target).y = _startPoint + _delta * 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)

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