Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > samana

Оценить эту запись

RastrMovieClip или свой велосипед

Запись от samana размещена 13.06.2014 в 02:06
Обновил(-а) samana 15.06.2014 в 23:01 (update)

Вступление
Конечно возможность перевода мувиклипа в растр - тема не новая и давно решённая множеством вариантов. Каждый автор создаёт своё творение, стараясь сделать ещё лучше, быстрее, удобнее! Статьи по этой теме я нашел на gamedevblogs и у Антона Карлова в его замечательном блоге, который знаком всем флешерам. Но всё равно захотелось сделать и свой вариант.

Класс представленный мной, конечно будет полезен только тем флешерам, которые создают анимацию во Flash IDE, и очень хотят побыстрее перевести свои мувиклипы в растр, печатая как можно меньше кода для этого. Работать с классом очень просто, ведь он практически такой же как и привычный MovieClip. Класс можно так же посмотреть на github, а демку почти в самом низу блога.


Как это работает и что новенького
Возможно многое здесь будет совершенно не новым, а просто я нахожусь в неведении. Но опишу на всякий случай для тех, кому интересно.
  • При кешировании мувиклипа создаётся массив с BitmapData, для каждого кадра. Размер картинки зависит от содержимой графики в кадре (так же как в первой ссылке выше). Этот кеш конечно висит в памяти и его можно использовать в любое время.
  • new Есть расчёт на то, если вдруг у мувиклипа оказался пустой кадр. Ошибки не возникнет, просто тогда в кеш попадает однопиксельная, прозрачная BitmapData.
  • new Если какие либо кадры у мувиклипа оказываются одинаковыми (с точки зрения содержащейся в них графики), то лишняя BitmapData создаваться не будет! В кеш запишется просто ссылка на найденную ранее копию. Поэтому в анимации можно смело ставить паузы, не беспокоясь о наличии одинаковых картинок, висящих в памяти, после перевода мувика в растр.
  • new Если к объекту применены какие нибудь фильтры (Blur, DropShadow, Glow и т.п.), частичного срезания графики фильтра при переводе в растр не случится. Рисунок показывает ту проблему, которую я имею ввиду.

    Название: filterOctopus.jpg
Просмотров: 946

Размер: 99.1 Кб

    Поэтому изначально раст для кадра делается чуть большего размера, чем границы полученные методом getBounds (на 100 px в каждую сторону, но можно изменить это значение в классе, оно называется offset). Затем уже по растру определяется область где содержится графика (getColorBoundsRect). В итоге эффект фильтров будет виден полностью и пустых областей не останется.
  • new Анимация всех вложенных мувиклипов будет видна!
    Если помните, то при draw мувиклипа, он рисуется в таком виде, каким представлен в библиотеке и анимация всех его детей-мувиклипов не играется. И только если каждому мувику установить тип Graphic, тогда анимация будет видна при draw.
    Поэтому в моём варианте не обязательно устанавливать во Flash IDE все вложенные мувиклипы в тип Graphic, хотя это часто бывает очень удобно при создании анимации.

С фишками наверно и всё. Теперь опишу публичные методы с маленькими фишечками.


Методы. Как управлять? Что умеет?

Создать растровый кеш для мувиклипа очень просто. Достаточно передать в конструктор - название класса того мувика, который нужно закешировать. Например:
Код AS3:
var rasrtMovie:RastrMovieClip = new RastrMovieClip(MyMovieClip_ClassName);
Мне очень часто было не удобно, когда нативный мувиклип начинал автоматически проигрывать анимацию, сразу же после создания. Поэтому анимация в моём варианте не запускается, и её необходимо будет запустить вручную. Конечно это зависит от ваших привычек, но мне было так удобнее.


Публичные методы

Действие методов понятны из их названия, но опишу их на всякий случай:

setAnimation(movieClipClass:Class,autoPlay:Boolean=false) - назначить новую анимацию. Если кеш для этой анимации ещё не был создан, то он создастся автоматически. Так как после смены анимации воспроизведение останавливается, то можно сразу запустить его, изменив autoPlay на true.

play(loop:Boolean = true) - начать воспроизведение анимации. По умолчанию она проигрывается циклически по кругу, но это можно легко исправить, установив параметр loop в false. Тогда анимация остановится в последнем кадре.

playRevers(loop:Boolean = true) - начать воспроизведение в обратную сторону. Установив параметр loop в false - анимация остановится на первом кадре, иначе будет проигрываться по кругу.

gotoAndPlay(frame:int, loop:Boolean = true) - работает так же как и в обычном мувиклипе, плюс можно проконтролировать зацикленность воспроизведения.

gotoAndPlayRevers(frame:int, loop:Boolean = true) - тоже самое что и метод выше, только с воспроизведением анимации в обратную сторону.

Следующие методы действуют почти так же, как в обычном MovieClip:

gotoAndStop(frame:int) - перейти на определённый кадр и остановится.

nextFrame() - перейти в следующий кадр.

prevFrame() - перейти в предыдущий кадр.

stop() - остановка анимации.

Внимание!!!
Во все методы, которые принимают номер кадра - можно передать любое число и это не вызовет ошибки. Номер кадра будет скорректирован либо в единицу - если число оказалось меньше чем 1, либо в число равное totalFrames - если число оказалось больше количества кадров.
К тому же, методы nextFrame и prevFrame будут проигрывать анимацию по кругу. Например если вы находитесь в последнем кадре и вызовите nextFrame, то перейдёте в первый кадр. У нативного MovieСlip такого не было, поэтому здесь тоже есть отличия.



И парочка нужных геттеров

currentAnimation():Class - возвращает имя класса (который был закеширован) текущей анимации. Если кеша не обнаружилось, то вернётся null.

isPlay():Boolean - узнать проигрывается ли анимация в данный момент.

totalFrames():int - возвращает общее количество кадров.

currentFrame():int - узнать номер текущего кадра.


Одно публичное свойство

smoothing:Boolean - сглаживание растра, по умолчанию отключено.


События

Событий всего два, при наступлении первого и последнего кадра.

При создании или смене анимации (setAnimation), по умолчанию кадр выставляется в единицу, но событие первого кадра в этот момент не происходит. Это сделано специально.

RastrMovieClip.FIRST_FRAME - текущий кадр первый.

RastrMovieClip.LAST_FRAME - текущий кадр последний.


Статичные методы

Их тоже всего два и оба для удаления кеша. Можно удалить кеш полностью, либо какой-то нужный.

RastrMovieClip.clearAmination(movieClipClass:Class) - удаляет кеш конкретного мувиклипа.

RastrMovieClip.clearAll() - полностью удаляет весь кеш.


Окончание

Немного дополнительной информации и советы.

При удалении со сцены, анимация автоматически останавливается. Поэтому после добавления обратно на сцену, не забудьте запустить анимацию.

Так как данный класс является наследником Sprite, вы можете добавлять в него другие визуальные объекты. Но будьте внимательны при манипуляциях с удалением детей. Чтобы случайно не удалить ту bitmap, которая находится в нём по умолчанию, которая показывает анимацию. Лучше всего будет просто не добавлять детей.

С label-ами данный класс ещё не дружит, поэтому они игнорируются.

Если вы вдруг заметите баги, сообщите о них и я постараюсь с ними договорится.


Небольшая демка для теста, в которой можно кликать. Профайлер доступен в меню через ПКМ.
NewProjectexpwithrastrMovieClip.swf   (19.5 Кб)

Исходник - проект FlashDevelop.

И напоследок - полотно класса, на случай если у кого-то нет желания скачивать исходник.
Пока я ещё не смог перейти на github, поэтому буду пополнять список обновлений здесь.
UPDATE

13.06.14
-> Теперь в конструктор по умолчанию не обязательно передавать параметр.
-> Переопределены методы с манипуляциями потомков. Чтобы _bitmap оставался неизменным. (toFL)
-> Созданы метатеги для событий. (toFL)
-> Оптимизация поиска одинаковых кадров. (515) (toFL)
-> Блокировка запуска анимации, если кадров меньше чем 2.
-> Добавлен параметр autoPlay:Boolean в метод setAnimation(), позволяющий начать воспроизведение сразу, после смены анимации.


RastrMovieClip.as
Код AS3:
package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
 
	/**
	 * Растеризует мувиклип в набор картинок.
	 *
	 * @author samana
	 * 
	 * @update 13.06.14
	 * 			-> Теперь в конструктор по умолчанию не обязательно передавать параметр.
	 * 			-> Переопределены методы с манипуляциями потомков. Чтобы _bitmap оставался неизменным.
	 * 			-> Созданы метатеги для событий.
	 * 			-> Оптимизация поиска одинаковых кадров. (515)
	 * 			-> Блокировка запуска анимации, если кадров меньше чем 2.
	 * 			-> Добавлен параметр autoPlay:Boolean в метод setAnimation(), позволяющий начать воспроизведение сразу, после смены анимации.
	 */
 
 
	/**
	 * События при наступлении первого и последнего кадра
	 */
	 [Event(name = "lastFrame", type = "RastrMovieClip")]
	 [Event(name = "firstFrame", type = "RastrMovieClip")]
 
	public class RastrMovieClip extends Sprite
	{
		/**
		 * Константы для событий первого и последнего кадров.
		 */
		static public const LAST_FRAME:String = "lastFrame";
		static public const FIRST_FRAME:String = "firstFrame";
 
		//==============================================
		//			STATIC PRIVATE
		//==============================================
		/**
		 * Словарь в котором хранятся массивы c набором BitmapData,
		 * для  каждого класса мувиклипа, который был переведён в растр.
		 */
		private static var _movieClipClasses:Dictionary = new Dictionary();
 
		/**
		 * Словарь в котором хранятся массивы с Point, для каждого
		 * отдельного кадра мувиклипа, который был переведён в растр.
		 * Так как кадр может быть разного размера (в зависимости от содержащейся в нём графики),
		 * положение bitmap надо постоянно менять.
		 */
		private static var _movieClipPositions:Dictionary = new Dictionary();
 
		//==============================================
		//			PRIVATE VARS
		//==============================================
		/**
		 * Имя класса текущего, кешированного мувиклипа.
		 */
		private var _currentAnimation:Class;
 
		//-------------------------
		//-------------------------
		/**
		 * Массив с BitmapData для каждого кадра
		 */
		private var _bitmapDates:Vector.<BitmapData>;
 
		/**
		 * Массив позиций для каждого кадра
		 */
		private var _bitmapsPos:Vector.<Point>;
 
		//-------------------------
		//-------------------------
 
		/**
		 * Кол-во кадров анимации.
		 */
		private var _totalFrames:int;
 
		/**
		 * Текущий кадр.
		 */
		private var _currentFrame:int = 1;
 
		/**
		 * Проигрывается ли анимация в данный момент.
		 */
		private var _isPlay:Boolean = false;
 
		/**
		 * Зацикленность анимации, по умолчанию - зациклена.
		 */
		private var _isLoop:Boolean = true;
 
		//-------------------------
		//-------------------------
 
		/**
		 * Bitmap, которая будет показывать текущий кадр. Добавляется в отображение.
		 */
		private var _bitmap:Bitmap;
 
		//==============================================
		//			PUBLIC VARS
		//==============================================
		/**
		 * Включение сглаживания для растра, влияет на производительность.
		 */
		public var smoothing:Boolean = false;
 
 
		/**
		 * @construstor
		 *
		 * @param	movieClipClass - класс мувиклипа, который нужно перевести в растр.
		 * 
		 */
		public function RastrMovieClip(movieClipClass:Class=null)
		{
			_bitmap = new Bitmap();
			addChild(_bitmap);
 
			if (movieClipClass) setAnimation(movieClipClass);
 
			addEventListener(Event.ADDED_TO_STAGE, addedToStage);
		}
 
 
		//==============================================
		//			PUBLIC METHODS
		//==============================================
		/**
		 * Назначает новую анимацию и переводит её в первый кадр.
		 * @param	movieClipClass - имя класса мувиклипа.
		 * @param 	autoPlay - начать воспроизведение, по умолчанию отключено.
		 */
		public function setAnimation(movieClipClass:Class,autoPlay:Boolean=false):void
		{
			stop();
 
			// растеризую мувик, если его кеша ещё нет
			if (_movieClipClasses[movieClipClass] == undefined)
			{
				createRastrMovie(movieClipClass);
			}
 
			//назначаю имя текущей анимации
			_currentAnimation = movieClipClass;
 
			//передаю приватным переменным ссылки на массивы картинок и их позиций из статических словарей
			//в которых хранится весь кеш. Так как доступ к приватной переменной быстрее, чем к статической.
			_bitmapDates = _movieClipClasses[movieClipClass];
			_bitmapsPos = _movieClipPositions[movieClipClass];
 
			_totalFrames = _bitmapDates.length;
			_currentFrame = 1;
 
			//показать картинку кадра
			_bitmap.bitmapData = _bitmapDates[_currentFrame - 1];
			_bitmap.x = _bitmapsPos[_currentFrame - 1].x;
			_bitmap.y = _bitmapsPos[_currentFrame - 1].y;
 
			//если надо, то запуситить анимацию.
			if (autoPlay) play();
		}
 
 
		/**
		 * Проигрывание анимации
		 * @param	loop - зацикленность анимации
		 */
		public function play(loop:Boolean = true):void
		{
			stop();
 
			//если кадр всего один, или кеш был удалён _totalFrames=0,
			//то анимацию не запусткаю.
			if (_totalFrames < 2) return;
 
			_isPlay = true;
			_isLoop = loop;
			addEventListener(Event.ENTER_FRAME, enterFramePlay);
		}
 
 
		/**
		 * Обратное проигрывание анимации.
		 * @param	loop - зацикленность анимации.
		 */
		public function playRevers(loop:Boolean = true):void
		{
			stop();
 
			//если кадр всего один, или кеш был удалён _totalFrames=0,
			//то анимацию не запусткаю.
			if (_totalFrames < 2) return;
 
			_isPlay = true;
			_isLoop = loop;
			addEventListener(Event.ENTER_FRAME, enterFrameRevers);
		}
 
 
		/**
		 * Остановка анимации.
		 */
		public function stop():void
		{
			_isPlay = false;
 
			if (hasEventListener(Event.ENTER_FRAME))
			{
				removeEventListener(Event.ENTER_FRAME, enterFramePlay);
				removeEventListener(Event.ENTER_FRAME, enterFrameRevers);
			}
		}
 
 
		//==============================================
		//			GO TO AND PLAY or STOP
		//==============================================
		/**
		 * Проигрывание анимации с определённого кадра.
		 *
		 * @param	frame - номер кадра с которого нужно начать воспроизведение.
		 * @param	loop - зацикленность для воспроизведения.
		 */
		public function gotoAndPlay(frame:int, loop:Boolean = true):void
		{
			_currentFrame = frame;
			play(loop);
		}
 
 
		/**
		 * Проигрывание анимации в обратном порядке с определённого кадра.
		 *
		 * @param	frame - номер кадра с которого нужно начать обратное воспроизведение.
		 * @param	loop - зацикленность для воспроизведения.
		 */
		public function gotoAndPlayRevers(frame:int, loop:Boolean = true):void
		{
			_currentFrame = frame;
			playRevers(loop);
		}
 
 
		/**
		 * Переход на выбранный кадр и остановка анимации.
		 * @param	frame - номер кадра.
		 */
		public function gotoAndStop(frame:int):void
		{
			_currentFrame = frame;
			stop();
			showFrame();
		}
 
 
		/**
		 * Переход на следующий кадр.
		 */
		public function nextFrame():void
		{
			_currentFrame++;
			showFrame();
		}
 
 
		/**
		 * Переход на предыдущий кадр.
		 */
		public function prevFrame():void
		{
			_currentFrame--;
			showFrame();
		}
 
 
		//==============================================
		//			STATIC PUBLIC METHODS
		//==============================================
		/**
		 * Удаляет кеш мувиклипа и освобождает память.
		 * @param	movieClipClass - класс мувиклипа, кеш которого надо удалить.
		 */
		public static function clearAmination(movieClipClass:Class):void
		{
			if (_movieClipClasses[movieClipClass] != undefined)
			{
				var bmdArr:Vector.<BitmapData> = _movieClipClasses[movieClipClass];
 
				while (bmdArr.length)
				{
					bmdArr[0].dispose();
					bmdArr[0] = null;
					bmdArr.shift();
				}
 
				delete _movieClipClasses[movieClipClass];
				delete _movieClipPositions[movieClipClass];
			}
 
			trace("Кеш мувиклипа", movieClipClass, "был удалён");
		}
 
 
		/**
		 * Удаляет кеш всех мувиклипов
		 */
		public static function clearAll():void
		{
			for (var name:Object in _movieClipClasses)
			{
				clearAmination(name as Class);
			}
		}
 
 
		//==============================================
		//			PRIVATE METHODS
		//==============================================
		/**
		 * Проигрывание анимации вперёд.
		 * @param	e - Event
		 */
		private function enterFramePlay(e:Event):void
		{
			//trace("plays");
			_currentFrame++;
			showFrame();
		}
 
 
		/**
		 * Проигрывание анимации назад.
		 * @param	e - Event
		 */
		private function enterFrameRevers(e:Event):void
		{
			//trace("playsRevers");
			_currentFrame--;
			showFrame();
		}
 
 
		/**
		 * Корректирует номер кадра, если его число вышло за пределы в обе стороны.
		 * Назначает нужную BitmapData для текущего кадра.
		 * Рассылает события в первом и последнем кадре.
		 */
		private function showFrame():void
		{
 
			// если кадр больше общего кол-ва кадров
			if (_currentFrame > _totalFrames)
			{
				// если loop то начинаем сначала
				if (_isLoop)
				{
					_currentFrame = 1;
				}
				else
				{
					// иначе останавливаемя в конце
					_currentFrame = _totalFrames;
					stop();
				}
			}
 
			// если кадр меньше чем 1, то
			if (_currentFrame < 1)
			{
				// если цикл включён - переходим на последний кадр
				if (_isLoop)
				{
					_currentFrame = _totalFrames;
				}
				// иначе переходим на первый кадр и останавливаемся.
				else
				{
					_currentFrame = 1;
					stop();
				}
 
			}
 
			//если вдруг кеш был удалён, то обнуляем все приватные массивы и 
			//останавливаем анимацию.
			if (_movieClipClasses[_currentAnimation] == undefined)
			{
				trace(this, "остановлен. Кеш для", currentAnimation, "не существует.");
				stop();
				_totalFrames = 0;
				_currentFrame = 0;
				_currentAnimation = null;
				_bitmap.bitmapData = null;
				_bitmapDates = null;
				_bitmapsPos = null;
				return;
			}
 
			//назначаю битмапДату текущего кадра
			_bitmap.bitmapData = _bitmapDates[_currentFrame - 1];
			_bitmap.x = _bitmapsPos[_currentFrame - 1].x;
			_bitmap.y = _bitmapsPos[_currentFrame - 1].y;
 
			_bitmap.smoothing = smoothing;
 
			//events
			if (_currentFrame == _totalFrames) 
			{
				dispatchEvent(new Event(LAST_FRAME));
			}
 
			if (_currentFrame == 1)
			{
				dispatchEvent(new Event(FIRST_FRAME));
			}
 
			//посмотреть границы клипа
			//graphics.clear();
			//var r:Rectangle = getBounds(this);
			//graphics.lineStyle(1, 0x0000FF);
			//graphics.drawRect(r.x, r.y, r.width, r.height);
		}
 
 
		/**
		 * Перевод мувиклипа в растр.
		 * @param	movieClipClass - класс мувиклипа, который нужно перевести в растр.
		 */
		private function createRastrMovie(movieClipClass:Class):void
		{
			trace("создан новый растр для", movieClipClass);
 
			//прозрачная битмапДата 1х1 для пустых кадров.
			var _emptyBMD:BitmapData = new BitmapData(1, 1, true, 0x00000000);
 
			//мувик который будем рендерить
			var mc:MovieClip = new movieClipClass() as MovieClip;
			mc.stop();
 
			//временное хранилищце для битмапДат и позиций
			var bmdVec:Vector.<BitmapData> = new Vector.<BitmapData>();
			var bmPos:Vector.<Point> = new Vector.<Point>();
 
			// ЦИКЛ равен кол-ву кадров 
			for (var i:int = 0; i < mc.totalFrames; i++)
			{
				//переходим по кадрам мувиклипа
				mc.gotoAndStop(i + 1);
 
				// РЕНДЕР КАДРА
				//значение на которое увеличится прямоугольник если вдруг там фильтр
				var offset:int = 100;
 
				//определяю прямоугольную область в которой расположен мувик в данном его кадре. 
				var rect:Rectangle = mc.getBounds(mc);
 
				//битмапДата для кадра
				var bmd:BitmapData;
 
				//если графики меньше чем пиксель или кадр пустой, то
				//передаём битмапДате - однопиксельную, заранее созданную битмапДату
				if (rect.width < 1 || rect.height < 1)
					bmd = _emptyBMD;
				//но если графика в кадре есть, то начинаем сдедующее.. 
				else
				{
					// увеличиваю прямоугольник (вдруг там фильтры)
					rect.x -= offset;
					rect.y -= offset;
					rect.width += offset * 2;
					rect.height += offset * 2;
 
					rect.x = int(rect.x);
					rect.y = int(rect.y);
					rect.width = int(rect.width);
					rect.height = int(rect.height);
 
					//рисую содержимое кадра
					bmd = new BitmapData(rect.width, rect.height, true, 0x00000000);
					bmd.draw(mc, new Matrix(1, 0, 0, 1, -rect.x, -rect.y));
 
					//нахожу область, где есть цвета (так как до этого была отрендерена область больше нужной)
					var rectColor:Rectangle = bmd.getColorBoundsRect(0xFFFFFFFF, 0x00000000, false);
					rectColor.x = int(rectColor.x);
					rectColor.y = int(rectColor.y);
					rectColor.width = int(rectColor.width);
					rectColor.height = int(rectColor.height);
 
					//если там были фильры, то возможно всё размыто в ноль,
					//либо все объекты в кадре полностью прозрачны.
					//Поэтому прямоугольная область снова может стать нулевой,
					//и если это так, то передаю пустую битмапДату
					if (rectColor.width < 1 || rectColor.height < 1)
					{
						bmd = _emptyBMD;
					}
					//а если содержимое всё же осталось, то
					else
					{
 
						//создаю новую битмапДату уже нужного размера
						var bmdFix:BitmapData = new BitmapData(rectColor.width, rectColor.height, true, 0x00000000);
						// копирую в неё графику кадра
						bmdFix.copyPixels(bmd, rectColor, new Point());
 
						bmd.dispose();
						bmd = null;
						bmd = bmdFix.clone();
 
						bmdFix.dispose();
						bmdFix = null;
 
						//корректирую положение прямоугольной области (положение для битмапы на сцене)
						rect.x += rectColor.x;
						rect.y += rectColor.y;
					}
 
				} // РЕНДЕР КАДРА конец
 
				//создаю временную позицию для положение битмапы текущего кадра на сцене
				var positionPoint:Point = new Point(rect.x, rect.y);
 
				//------------------------------------------------------------------------------------------
				//найти такую же битмапдату (если кадры не оличаются)
				//и передать на неё ссылку (чтобы не создавать одинаковых данных)
				var bmdV:BitmapData;
				var bmdVec_length:int = bmdVec.length
 
				for (var j:int = 0; j < bmdVec_length; j++)
				{
					bmdV = bmdVec[j];
					//если битмапДаты не отличаются
					if (bmd.width == bmdV.width && bmd.height == bmdV.height && bmd.compare(bmdV) == 0)
					{
						//trace("кадр:", i + 1, "такой же как кадр:", j + 1)
						bmd = bmdVec[j];
						positionPoint = bmPos[j];
						break;
					}
				}
				//------------------------------------------------------------------------------------------
 
				//заношу в массив отрендеренный кадр
				bmdVec[i] = bmd;
				//и в другой массив заношу координаты для битмапы этого кадра
				bmPos[i] = positionPoint;
 
				//------------------------------------------------------------------------------------------
				//перебрать все вложенные мувики и передвинуть их анимацию вперёд,
				//Делается это уже после рендера кадра, чтобы не пропустить первый кадр любого вложенного ребёнка.
				//А если этот ребёнок встретится и на следующем кадре, то его анимация уже перейдёт на кадр вперёд, то что и надо.
				nextFrameChildren(mc);
 
				//локалный метод. Поиск всех детей в текущем кадре мувиклипа.
				//Если среди них есть мувиклип, то переводим его анимацию на кадр вперёд (loop)
				function nextFrameChildren(obj:DisplayObject):void
				{
					if (obj is MovieClip)
					{
						var mclip:MovieClip = obj as MovieClip;
 
						for (var k:int = 0; k < mclip.numChildren; k++)
						{
							if (mclip.getChildAt(k) is MovieClip)
							{
								var mcChild:MovieClip = mclip.getChildAt(k) as MovieClip;
 
								if (mcChild.currentFrame == mcChild.totalFrames)
									mcChild.gotoAndStop(1);
								else
									mcChild.nextFrame();
 
								nextFrameChildren(mcChild);
							}
						}
					}
				}
				//------------------------------------------------------------------------------------------
 
			}
 
			// КОГДА все кадры отрендерены, сохраняю кеш в статических словарях.
 
			//помещаю набор битмапДат отрендеренного мувика - в статический словарь для картинок
			//и так же помещаю набор координат для каждого кадра мувика - в статичечкий словарь для позиций
			_movieClipClasses[movieClipClass] = bmdVec;
			_movieClipPositions[movieClipClass] = bmPos;
		}
 
 
		/**
		 * Добавление и удаление со сцены.
		 */
		private function addedToStage(e:Event):void
		{
			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
		}
 
 
		/**
		 * При удалении со сцены, останавливаем проигрывание анимации.
		 */
		private function removedFromStage(e:Event):void
		{
			removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
			stop();
		}
 
 
		//==============================================
		//			GETTERS SETTERS
		//==============================================
		/**
		 * Узнать текущий кадр.
		 */
		public function get currentFrame():int
		{
			return _currentFrame;
		}
 
 
		/**
		 * Узнать кол-во кадров.
		 */
		public function get totalFrames():int
		{
			return _totalFrames;
		}
 
 
		/**
		 * Узнать проигрывается ли в данный момент анимация.
		 */
		public function get isPlay():Boolean
		{
			return _isPlay;
		}
 
 
		/**
		 * Узнать имя класса текущей анимации.
		 */
		public function get currentAnimation():Class
		{
			return _currentAnimation;
		}
 
 
 
		//==============================================
		//			OVERRIDE CHILDREN METHODS
		//==============================================
		/**
		 * Переопределят все манимипуляции с потомками, чтобы не удлалить
		 * _bitmap, который является главной анимацией
		 */
 
		override public function removeChild(child:DisplayObject):DisplayObject 
		{
			if (child == _bitmap) return null;
			return super.removeChild(child);
		}
 
		override public function removeChildAt(index:int):DisplayObject 
		{
			if (super.getChildAt(index) == _bitmap) return null;
			return super.removeChildAt(index);
		}
 
		override public function removeChildren(beginIndex:int = 1, endIndex:int = 2147483647):void 
		{
			super.removeChildren(beginIndex, endIndex);
		}
 
		override public function swapChildren(child1:DisplayObject, child2:DisplayObject):void 
		{
			if (child1 == _bitmap || child2 == _bitmap) return;
			super.swapChildren(child1, child2);
		}
 
		override public function swapChildrenAt(index1:int, index2:int):void 
		{
			if (super.getChildAt(index1) == _bitmap || super.getChildAt(index2) == _bitmap) return;
			super.swapChildrenAt(index1, index2);
		}
 
		override public function addChildAt(child:DisplayObject, index:int):DisplayObject 
		{
			if (index == 0) index=1;
			return super.addChildAt(child, index);
		}
 
		override public function getChildAt(index:int):DisplayObject 
		{
			if (index == 0) return null;
			return super.getChildAt(index);
		}
 
		override public function getChildByName(name:String):DisplayObject 
		{
			if (super.getChildByName(name) == _bitmap) return null;
			return super.getChildByName(name);
		}
 
	}
 
}
Вложения
Тип файла: swf NewProjectexpwithrastrMovieClip.swf (19.5 Кб, 577 просмотров)
Тип файла: rar exp with rastrMovieClip.rar (72.5 Кб, 156 просмотров)
Всего комментариев 31

Комментарии

Старый 13.06.2014 22:49 toFL вне форума
toFL
Цитата:
на 100 px в каждую сторону, но можно изменить это значение в классе, оно называется offset
Я уже говорил об этой проблеме. У меня есть класс, который со 100% выдаст реальные размеры DisplayObjectContainer со всей вложенностью фильтров, при этом без лишних расходов. Посмотреть можно в публичных сообщениях пользователя: Котяра.
Желаю успехов
Старый 13.06.2014 22:53 toFL вне форума
toFL
Цитата:
Но будьте внимательны при манипуляциях с удалением детей. Чтобы случайно не удалить ту bitmap, которая находится в нём по умолчанию, которая показывает анимацию. Лучше всего будет просто не добавлять детей.
Советую переопределить методы addChildAt, removeChildAt и т.п. что б феншуйно было.
Обновил(-а) toFL 13.06.2014 в 23:03
Старый 13.06.2014 23:05 toFL вне форума
toFL
Цитата:
Событий всего два, при наступлении первого и последнего кадра.
Такие штуки лучше объявлять метатэгом Event перед объявлением класса. Тогда, если набрать instance.addEventListener, сразу будет подсказка какие возможны события.
Старый 13.06.2014 23:18 samana вне форума
samana
 
Аватар для samana
Спасибо toFL, очень ценные советы! Буду обязательно улучшать класс и обновлять пост!
Старый 13.06.2014 23:18 toFL вне форума
toFL
  1. Не дергаем длину вектора
  2. ++j быстрее чем j++
Код AS3:
var len:int = bmdVec.length;
for (var j:int = 0; j < len; ++j)
  1. Такая проверка реже будет вызывать сравнение большого кол-ва пикселей (4byte*width*height)
  2. Уходим от излишнего поиска элемента в векторе по индексу
Код AS3:
var bd:BitmapData = bmdVec[j];
if (bmd.width == bd.width && bmd.height == bd.height && bmd.compare(bd) == 0)
	bmd = bd;
	positionPoint = bmPos[j];
	break;
}
Старый 13.06.2014 23:31 samana вне форума
samana
 
Аватар для samana
Классно!!! Блин, мне стыдно, почему я сам до этого не додумался..)
Правда я ещё даже не пытался оптимизировать класс, надо этим заняться вплотную, как можно раньше.
Старый 14.06.2014 00:01 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
Цитата:
++j быстрее чем j++
На сколько?
Старый 14.06.2014 11:55 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Вообще круто, 300 зомби - 30 fps, 350 -> 25 fps. Я уже не в теме флеша, эта поделка интегрируется со старлингом или это другой вид рендера?
Старый 14.06.2014 12:41 Tails вне форума
Tails
 
Аватар для Tails
cpu рендер.
Старый 14.06.2014 12:52 samana вне форума
samana
 
Аватар для samana
Psycho Tiger, спасибо. Нет, со старлингом не интегрируется, как уже подсказал Tails - это родной рендер.
Старый 14.06.2014 12:56 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
Сделайте репозиторий на github
Старый 14.06.2014 14:28 samana вне форума
samana
 
Аватар для samana
СлаваRa, похоже когда нибудь придётся всё таки это сделать. Помню в предыдущем блоге, мне тоже посоветовали воспользоваться github-ом, но я так и не осилил эту идею.
Старый 14.06.2014 14:59 MikroAcse вне форума
MikroAcse
 
Аватар для MikroAcse
TortoiseGit и легко разобраться.
Старый 14.06.2014 17:06 samana вне форума
samana
 
Аватар для samana
С github-ом я похоже пролетаю, так как для него необходим хотя бы Windows 7, а у меня выше XP - компьютер не потянет.
MikroAcse, спасибо за вариант, посмотрел. Но наверно не судьба у меня разобраться. Смотрю на эти git-ы, как крестьянин из 15 века на IPhone. Вообще почти ничего не понимаю, становлюсь от этого злым и кровожадно улыбаюсь.
Кстати, посмотрел на реализацию конвертирования мувика в растр, в исходных кодах Антона Карлова на том же github (до этого момента я её не видел) и оказывается у него все мои фишки (я считал что их ещё небыло) давным-давно сделаны и намного грамотней, чем у меня) Так что мой класс оказался действительно - велосипедом с рамой. Но ничего, по крайней мере это был опыт, а опыт это всегда - хорошо.
Старый 14.06.2014 17:48 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Вроде как гайдик для ХР.
http://mrsimonelliott.com/blog/setti...hub-windows-xp
Старый 14.06.2014 21:57 samana вне форума
samana
 
Аватар для samana
Цитата:
Вроде как гайдик для ХР.
Всё равно ничего не понимаю к сожалению, но благодарю за попытку помочь мне.
Старый 15.06.2014 00:40 MikroAcse вне форума
MikroAcse
 
Аватар для MikroAcse
Цитата:
Но наверно не судьба у меня разобраться. Смотрю на эти git-ы, как крестьянин из 15 века на IPhone.
Пфф, как будто я что-то понимаю
Я никаких комманд не знаю гита, только GUI.
Старый 15.06.2014 14:22 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Не знаю никаких GUI гита, только команды

samana, это инвестиции в себя. Кем бы ты не работал, если дело касается IT в любом проявлении (даже написание обычных текстов!) – VCS обязателен. Среди всех возможных сейчас явно лидирует git, и, я думаю, ближайшие лет 5 ситуация не изменится.
Старый 15.06.2014 14:48 samana вне форума
samana
 
Аватар для samana
Мне и самому хотелось бы понять как всем этим пользоваться, так как вижу, что это удобная и интересная идея. И очень неожиданно для себя столкнулся с абсолютным непониманием этой технологии.. Все пользуются нормально, а я как-то отличился. Всё равно конечно буду пробовать понять это всё, хоть как нибудь, по урокам или видео. Просто ещё очень странно, что надо знать команды, какие-то ключи и т.п, вместо того, чтобы нажимать кнопочки). Слишком сложно для меня это сейчас и напоминает Linux, где тоже надо прописывать миллион команд, казалось бы в совершенно простых ситуациях.
Старый 15.06.2014 14:54 alexandrratush вне форума
alexandrratush
 
Аватар для alexandrratush
samana вот вам учебники для быстрого старта:
http://git-scm.com/book/ru/%D0%92%D0...BD%D0%B8%D0%B5
http://githowto.com/ru
Старый 15.06.2014 18:32 samana вне форума
samana
 
Аватар для samana
Спасибо, alexandrratush. Мне конечно уже попадались эти материалы, штудирую гугл целый день. Уже вроде всё сделал, но почему-то никак не получается залить файлы на репозитарий, выводит ошибку. Пытаюсь разобраться, что я сделал не так.
Старый 15.06.2014 21:44 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Пиши сюда ошибку, помогу.
Старый 15.06.2014 21:51 toFL вне форума
toFL
Цитата:
++j быстрее чем j++
Цитата:
На сколько?
По моим тестам: от 2 до 15%, в зависимости от условий использования. Результаты отличаются на разных OS, на разных архитектурах CPU и т.п. Но в любом случае, как ни крути, быстрее.
Старый 15.06.2014 21:54 toFL вне форума
toFL
К тому же математические операции на Android выполняются (в среднем) в 2 раза медленнее, чем на iOS. И в 30 раз медленнее чем на Windows. Поэтому я за такими вещами пристально гляжу.
Старый 15.06.2014 22:36 samana вне форума
samana
 
Аватар для samana
Кажется получилось! Класс всё же переехал на github по адрессу - https://github.com/samana1407
Но не знаю что будет дальше, и получится ли правильно пользоваться. Возможно я случайно что-то удалю или напутаю. Ещё не разобрался со всем этим богатством, так что если внезапно проект исчезнет - не удивляйтесь.
Спасибо всем, кто поддерживал в освоении github!
Старый 16.06.2014 21:47 illuzor вне форума
illuzor
 
Аватар для illuzor
Цитата:
Возможно я случайно что-то удалю или напутаю.
Всегда можно откатиться.
Старый 30.03.2022 11:22 Alexey25 вне форума
Alexey25
В RastrMovieClip присутсвует метод "removeChildren", который переопределен override, но основного метода нет, поэтому если использовать override то появится такая ошибка:
Цитата:
override public function removeChildren(beginIndex:int = 1, endIndex:int = 2147483647):void
Соответственно ничего не запустить. Здесь или надо дописать код или вообще убрать, removeChildren. Может требуется подключить дополнительную библиотеку?
Старый 08.04.2022 18:35 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
@Alexey25, посмотрите по документации с какой версии плеера появился этот метод и сравните со своей
Старый 12.04.2022 12:58 Alexey25 вне форума
Alexey25
@СлаваRa, я просто закомментировал этот метод и все заработало.
Старый 14.04.2022 18:49 СлаваRa вне форума
СлаваRa
 
Аватар для СлаваRa
@Alexey25, да, это гораздо лучше чем понять в чем проблема была
Старый 15.04.2022 03:13 Alexey25 вне форума
Alexey25
Просто у меня Flash старая версия CS 4 (Adobe Flash 10). Поэтому выполнить примеры с новыми методами не получится.
 
Последние записи от samana

 


Часовой пояс GMT +4, время: 19:15.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.