![]() |
|
||||||||||
|
|||||||
|
|
« Предыдущая тема | Следующая тема » |
| Опции темы | Опции просмотра |
|
![]() |
![]() |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
Есть мувиклип Tw1, содержащий моушн-твин.
К нему привязан класс Tw1, через галочку Export to ActionScript. Необходимо вывести его на стэйдж и проиграть определенное количество раз, а затем остановить. На первый взгляд вроде бы простая задача, но очевидного решения придумать не удалось. Поиском по форуму нашел вот этот пост, в котором есть похожие мотивы. В результате получился такой код: 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. Есть ли другой способ решить эту задачу? Странно, но похоже на то, что нет. Ведь обязательно нужно знать момент окончания мувиклипа, а это достигается только условием и вроде бы никак иначе. Выходит, никакими там комбинациями методов stop(); gotoAndStop(); play(); и т.п. это сделать нельзя. 2. Не понимаю, почему не работает строка: если ёё раскомментировать, то будет получена ошибка: Цитата:
|
|
|||||
|
на самом деле все верно.
метод removeChild в качестве параметра принимает DisplayObject, а вы ему пытаетесь подсунуть Object, для того чтобы не было ошибки, можете сделать так: или так:
__________________
местонахождение |
|
|||||
|
Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
|
на счет первого вопроса: По сути делать надо именно так и ни как иначе. Для упрощения вы можете написать класс у которого есть метод playAmount(count:uint=1) в которой можно передавать количество проигрываний и делать все действия для проверки внутри этого класса.
__________________
FlashPress.ru | Blog |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
СлаваRa, вот оно что, спасибо, так работает.
Интересно, а если бы была обратная ситуация, метод хочет Object, а ему суют DisplayObject, то оно прокатило бы? Предполагаю, что должно, ведь DisplayObject ниже по иерархии. maincode, Ясно, значит догадки были верны. Цитата:
Получилось вот так: Основной класс: 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); } } } } } 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. |
|
|||||
|
Регистрация: Feb 2010
Адрес: Город суеты
Сообщений: 191
|
на счет второго пункта - я именно так и предполагал, сейчас накидаю пример
Добавлено через 7 минут Можно сделать так: 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); } } } 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(); } } } Можно еще расширить класс MovieClip добавить в него метод playAmount, и вызывать его напрямую tw1.playAmount(3), но я бы использовал первый вариант.
__________________
FlashPress.ru | Blog |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
maincode, отлично, большое вам спасибо за готовый код.
Проверил у себя, всё работает. Практически всё понятно, кроме некоторых деталей: 1. Как определить, что именно должен расширять класс? Вот у вас Означает ли это, что если бы я, действуя механически, сделал бы extends Sprite, то... Кстати, сделал Sprite... думал будет ошибка, но нет - всё работает : ) Я думал может быть в случае Sprite не будут работать addEventListener'ы однако все ОК. 2. Зачем отдельная функция stop(); разве это не вызывает конфликта с системной функцией stop()? Как я понимаю, должен быть override в таких случаях, же. Но раз работает, значит не должен, хм. И зачем кстати дублирование идет? То есть идет: if (currentCount == totalCount) { mc.stop(); mc.removeEventListener(Event.ENTER_FRAME, frameHandler); } public function stop():void { mc.removeEventListener(Event.ENTER_FRAME, frameHandler); mc.stop(); } В принципе если последнюю функцию закоментировать, то всё работает как и раньше. |
|
|||||
|
Регистрация: 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: 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')); } } }
__________________
FlashPress.ru | Blog |
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
maincode, теперь всё понятно, благодарю за исчерпывающие ответы.
|
|
|||||
|
Регистрация: Mar 2013
Сообщений: 290
|
Вот еще вопрос, а как в этом фрагменте:
if (currentCount == totalCount) { mc.stop(); mc.removeEventListener(Event.ENTER_FRAME, frameHandler); } Казалось бы: Должно было сработать, однако нет, видимо потому, что у нас наследование от EventDispatcher, который не имеет метода removeChild(). Но как тогда? (Если сделать наследование от MovieClip, то тогда этот же оператор выдает: Цитата:
|
![]() |
![]() |
Часовой пояс GMT +4, время: 12:53. |
|
|
« Предыдущая тема | Следующая тема » |
| Теги |
| количество повторов , количество раз , мувиклип |
|
|