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

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 13.08.2013, 12:04
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 1  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
По умолчанию MovieClip: проиграть нужное число раз

Есть мувиклип Tw1, содержащий моушн-твин.
К нему привязан класс Tw1, через галочку Export to ActionScript.

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

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

В результате получился такой код:
Код AS3:
package
{
	  import flash.display.*;
	  import flash.events.*;
	  import flash.text.*;
 
	  public class Main extends Sprite
	  {
 
			  private var tw1:Tw1;
			  private var txt1:TextField;
			  private var playCounter:uint = 1;
 
			  public function Main()
			  {
				  //--- Выводим мувиклип ---//
				  tw1 = new Tw1();
				  tw1.x = 100;
				  tw1.y = 100;
				  tw1.name = "Instance1";
				  addChild(tw1);
 
				  //--- Выводим счётчик фрэймов ---//
				  txt1 = new TextField();
				  txt1.x = 10;
				  txt1.y = 300;
				  txt1.autoSize = TextFieldAutoSize.LEFT;
				  txt1.text = "None";
				  addChild(txt1);
 
				  tw1.addEventListener(Event.ENTER_FRAME, cycleListener);
			  }
 
			  private function cycleListener(e:Event):void
			  {
 
 
					  txt1.text = e.currentTarget.currentFrame.toString();
 
					  if (e.currentTarget.currentFrame == e.currentTarget.totalFrames  && playCounter <= 3)
					  {
							playCounter ++;
					  }
					  else if (playCounter > 3)
					  {
							tw1.stop();
							e.currentTarget.removeEventListener(Event.ENTER_FRAME, cycleListener);
//							removeChild(e.currentTarget);  
					  }
 
			  }
 
	  }
 
 
}
Вобщем, всё работает ОК, но есть два вопроса:

1. Есть ли другой способ решить эту задачу? Странно, но похоже на то, что нет.
Ведь обязательно нужно знать момент окончания мувиклипа, а это достигается только условием
Код AS3:
e.currentTarget.currentFrame == e.currentTarget.totalFrames
и вроде бы никак иначе.
Выходит, никакими там комбинациями методов stop(); gotoAndStop(); play(); и т.п. это сделать нельзя.

2. Не понимаю, почему не работает строка:
Код AS3:
//							removeChild(e.currentTarget);
если ёё раскомментировать, то будет получена ошибка:
Цитата:
1118: Implicit coercion of a value with static type Object to a possibly unrelated type flash.display: DisplayObject.
removeChild(e.currentTarget);
Чего-то чтоли уже не существует, или нужно преобразование типов?

Старый 13.08.2013, 12:49
СлаваRa вне форума Посмотреть профиль Отправить личное сообщение для СлаваRa Найти все сообщения от СлаваRa
  № 2  
Ответить с цитированием
СлаваRa
 
Аватар для СлаваRa

блогер
Регистрация: Feb 2008
Адрес: http://playtika.com
Сообщений: 1,119
Записей в блоге: 5
Отправить сообщение для СлаваRa с помощью ICQ Отправить сообщение для СлаваRa с помощью Skype™
на самом деле все верно.
метод removeChild в качестве параметра принимает DisplayObject, а вы ему пытаетесь подсунуть Object, для того чтобы не было ошибки, можете сделать так:
Код AS3:
removeChild(e.currentTarget as DisplayObject);
или так:
Код AS3:
removeChild(DisplayObjejct(e.currentTarget));
__________________
местонахождение

Старый 13.08.2013, 13:26
maincode вне форума Посмотреть профиль Отправить личное сообщение для maincode Посетить домашнюю страницу maincode Найти все сообщения от maincode
  № 3  
Ответить с цитированием
maincode

Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
на счет первого вопроса: По сути делать надо именно так и ни как иначе. Для упрощения вы можете написать класс у которого есть метод playAmount(count:uint=1) в которой можно передавать количество проигрываний и делать все действия для проверки внутри этого класса.
__________________
FlashPress.ru | Blog

Старый 13.08.2013, 16:07
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 4  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
СлаваRa, вот оно что, спасибо, так работает.
Интересно, а если бы была обратная ситуация, метод хочет Object, а ему суют DisplayObject, то оно прокатило бы?
Предполагаю, что должно, ведь DisplayObject ниже по иерархии.

maincode, Ясно, значит догадки были верны.

Цитата:
Для упрощения вы можете написать класс у которого есть метод playAmount(count:uint=1) в которой можно передавать количество проигрываний и делать все действия для проверки внутри этого класса.
Хм, интересная задача. Хотя не совсем понятно, что можно увести в класс, а что надо оставить.
Получилось вот так:

Основной класс:
Код AS3:
 
package
{
	  import flash.display.*;
	  import flash.events.*;
	  import flash.text.*;
 
	  public class Main extends Sprite
	  {
 
			  private const PLAY_NUMBER:uint = 3;
			  private var tw1:Tw1;
			  private var rCheck:RepeatCheck;
			  private var stopFlag:Boolean;
 
			  public function Main()
			  {
				  //--- Выводим мувиклип ---//
				  tw1 = new Tw1();
				  tw1.x = 100;
				  tw1.y = 100;
				  tw1.name = "Instance1";
				  addChild(tw1);
 
				  //--- Добавляем слушатель ---//
				  tw1.addEventListener(Event.ENTER_FRAME, cycleListener);
 
				  //--- Создаем экземпляр проверочного класса ---//
				  rCheck = new RepeatCheck();
 
			  }
 
			  private function cycleListener(e:Event):void
			  {
 
				  //--- Получаем флаг в зависимости от количества повторов ---//
				  stopFlag = rCheck.playAmount(PLAY_NUMBER);
 
				  if(stopFlag)
				  {
					 if (e.currentTarget.currentFrame == e.currentTarget.totalFrames)
					  {
							rCheck.playCounter ++;
					  }  
					  else if (rCheck.playCounter >= PLAY_NUMBER)
					  {
							tw1.stop();
							e.currentTarget.removeEventListener(Event.ENTER_FRAME, cycleListener);
							removeChild(e.currentTarget as DisplayObject); 
					  }
				  }
 
			  }
 
	  }
 
}
Класс, содержащий условия:

Код AS3:
package
{
	 public class RepeatCheck
	 {
 
		 public var playCounter:uint = 0;  
		 public function RepeatCheck()
		 {
			//empty constructor 
		 }
 
		 public function playAmount(count:uint = 1):Boolean
		 {
 
			if (playCounter <= count)
			{
				return true;
			}
			else
			{
				return false;
			}
		 }
 
	 }
}
Хотя, помоему, получилось как-то не очень изящно и грамотно.
И свойства с методами этого класса все public, что наверное тоже не очень хорошо.

Мне пока еще непросто сообразить как межклассовую логику лучше организовать.
Хотелось бы поэтому поводу еще два вопроса задать:

1. Можно ли как-то грамотнее второй класс сделать, чтобы условий в Main было еще меньше. А в RepeatCheck побольше.

2. Можно ли вообще сделать радикальный ход: функцию в слушателе cycleListener сделать методом этого отдельного класса?
Чтобы все условия с e.currentTarget'ами обрабатывались тоже в отдельном классе?

И тогда Main класс содержал бы только свой конструктор, и всё.
Я пробовал так зделать, но для моего уровня это сложно, непонятно как в другом классе обращаться со всеми этими свойствами событий.


Последний раз редактировалось Fogflasher; 13.08.2013 в 16:19.
Старый 13.08.2013, 16:21
maincode вне форума Посмотреть профиль Отправить личное сообщение для maincode Посетить домашнюю страницу maincode Найти все сообщения от maincode
  № 5  
Ответить с цитированием
maincode

Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
на счет второго пункта - я именно так и предполагал, сейчас накидаю пример

Добавлено через 7 минут
Можно сделать так:
Код AS3:
package
{
	import flash.display.Sprite;
 
	public class Main extends Sprite
	{
		private var tw1:Tw1;
		private var player:PlayerMC;
		public function Main()
		{
			tw1 = new Tw1();
			tw1.x = 100;
			tw1.y = 100;
			tw1.name = "Instance1";
			addChild(tw1);
			//
			player = new PlayerMC(tw1);
			player.playAmount(3);
		}
	}
}
Код AS3:
package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.EventDispatcher;
 
	public class PlayerMC extends EventDispatcher
	{
		private var mc:MovieClip;
		public function PlayerMC(mc:MovieClip)
		{
			this.mc = mc;
			mc.stop();
		}
 
		private var totalCount:uint;
		private var currentCount:uint;
		private function frameHandler(event:Event):void
		{
			if (mc.currentFrame == mc.totalFrames) {
				currentCount++;
			}
			if (currentCount == totalCount) {
				mc.stop();
				mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
			}
		}
 
 
		public function playAmount(count:uint=1):void
		{
			this.totalCount = count;
			this.currentCount = 0;
			//
			mc.addEventListener(Event.ENTER_FRAME, frameHandler);
			mc.play();
		}
 
		public function stop():void
		{
			mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
			mc.stop();
		}
	}
}
Т.е. класс PlayerMC не является визуальным, это всего лишь контроллер для управления анимацией.

Можно еще расширить класс MovieClip добавить в него метод playAmount, и вызывать его напрямую tw1.playAmount(3), но я бы использовал первый вариант.
__________________
FlashPress.ru | Blog

Старый 13.08.2013, 17:23
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 6  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
maincode, отлично, большое вам спасибо за готовый код.

Проверил у себя, всё работает.
Практически всё понятно, кроме некоторых деталей:

1. Как определить, что именно должен расширять класс?
Вот у вас
Код AS3:
PlayerMC extends EventDispatcher.
Означает ли это, что если бы я, действуя механически, сделал бы extends Sprite, то...
Кстати, сделал Sprite... думал будет ошибка, но нет - всё работает : )
Я думал может быть в случае Sprite не будут работать addEventListener'ы однако все ОК.

2. Зачем отдельная функция stop(); разве это не вызывает конфликта с системной функцией stop()?
Как я понимаю, должен быть override в таких случаях, же. Но раз работает, значит не должен, хм.
И зачем кстати дублирование идет? То есть идет:
Код AS3:
if (currentCount == totalCount)
{
 mc.stop();
 mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
}
и:

Код AS3:
 
public function stop():void
		{
			mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
			mc.stop();
		}
В обоих одинаковые ремув-листенеры... зачем так?
В принципе если последнюю функцию закоментировать, то всё работает как и раньше.

Старый 13.08.2013, 17:50
maincode вне форума Посмотреть профиль Отправить личное сообщение для maincode Посетить домашнюю страницу maincode Найти все сообщения от maincode
  № 7  
Ответить с цитированием
maincode

Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
1) я его расширил от EventDispatcher на автомате, т.к. если бы я писал полноценный класс, я бы сделал еще и отправку собственного события COMPLETE в момент когда закончилось проигрывание анимации. Т.е. что бы иметь возможность вызвать метод dispatchEvent, нужно наследоваться от класса EventDispatcher(или его наследника, или класса реализующего интерфейс IEventDispatcher).

Нет смысла наследоваться от Sprite потому, что класс PlayerMC не является визуальным, т.е. нам не нужно добавлять его на stage методом addChild(...), и поэтому нет смысла расширять его от класса Sprite.

Если все таки унаследоваться от класса Sprite - то ошибки не будет, т.к. Sprite является наследником класса EventDispatcher, см внимательно документацию:



2) Написал метод stop только ради чистоты кода, что бы класс PlayerMC имел методы не только для начала проигрывания, но и для остановки проигрывания в любой момент из класса Main. Override здесь писать не нужно, потому что класс PlayerMC наследуется от класса EventDispatcher, а этот класс EventDispatcher не имеет метода stop. Вот если бы вы написали PlayerMC extends MovieClip, тогда пришлось бы писать override, т.к. у базового класса есть метод stop()


3) "В обоих одинаковые ремув-листенеры... зачем так?" - это затем, что первый вызывается после окончания проигрывания системой, а метод stop можно вызывать из Main-а что бы принудительно остановить проигрывание в любой момент. Можно было бы написать в обработчике frameHandler вызов метода stop, но это плохая практика, лучше изолировать код который выполняется внутри класса, от методов которые вызываются снаружи. Если очень хочется объединить два одинаковых кода, можно написать еще один private метод stopAnimation:
Код AS3:
package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.EventDispatcher;
 
	public class PlayerMC extends EventDispatcher
	{
		private var mc:MovieClip;
		public function PlayerMC(mc:MovieClip)
		{
			this.mc = mc;
			mc.stop();
		}
 
		private var totalCount:uint;
		private var currentCount:uint;
		private function frameHandler(event:Event):void
		{
			if (mc.currentFrame == mc.totalFrames) {
				currentCount++;
			}
			if (currentCount == totalCount) {
				stopAnimation();
				this.dispatchEvent(new Event('completeAnim'));
			}
		}
 
		private function stopAnimation():void
		{
			mc.stop();
			mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
		}
 
 
		public function playAmount(count:uint=1):void
		{
			this.totalCount = count;
			this.currentCount = 0;
			//
			mc.addEventListener(Event.ENTER_FRAME, frameHandler);
			mc.play();
		}
 
		public function stop():void
		{
			stopAnimation();
			this.dispatchEvent(new Event('stopAnim'));
		}
	}
}
В этом коде я показал пример зачем необходимо изолировать внутренний вызов от внешнего: в примере выше генерируются два события: stopAnim - в момент когда вызываем метод stop из вне, и событие completeAnim в момент когда проигрывание дошло до конца и остановилось.
Миниатюры
Нажмите на изображение для увеличения
Название: sprite.png
Просмотров: 912
Размер:	159.8 Кб
ID:	29895  
__________________
FlashPress.ru | Blog

Старый 13.08.2013, 17:57
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 8  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
maincode, теперь всё понятно, благодарю за исчерпывающие ответы.

Старый 22.08.2013, 16:28
Fogflasher вне форума Посмотреть профиль Отправить личное сообщение для Fogflasher Найти все сообщения от Fogflasher
  № 9  
Ответить с цитированием
Fogflasher

Регистрация: Mar 2013
Сообщений: 290
Вот еще вопрос, а как в этом фрагменте:

Код AS3:
if (currentCount == totalCount)
{
 mc.stop();
 mc.removeEventListener(Event.ENTER_FRAME, frameHandler);
}
Записать оператор удаления текущего мувиклипа mc со стэйдж?

Казалось бы:

Код AS3:
this.removeChild(mc);
Должно было сработать, однако нет, видимо потому, что у нас наследование от EventDispatcher, который не имеет метода removeChild().

Но как тогда?

(Если сделать наследование от MovieClip, то тогда этот же оператор выдает:
Цитата:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display:: DisplayObjectContainer/removeChild()
at PlayerMC/::frameHandler()
)

Создать новую тему Ответ Часовой пояс GMT +4, время: 13:55.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Теги
количество повторов , количество раз , мувиклип
Опции темы
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


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