Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Пользовательские события. Композиция. (http://www.flasher.ru/forum/showthread.php?t=211841)

бакуард 19.11.2015 13:01

Пользовательские события. Композиция.
 
Доброго времени суток.

Разрабатываю небольшую игру. Проблема возникла когда реализовывал смерть персонажа. Чтобы оповестить
все классы о смерти персонажа решил использовать собственное событие. Поскольку класс персонажа уже расширяет класс Sprite, а реализовывать интерфейс IEventDipatcher не очень хочется (просто не знаю как) решил создать отдельный класс расширяющий EventDispatcher. Внутри этого класса есть открытый метод внутри которого создается новое событие.
В классе персонажа создается экземпляр класса унаследованного от EventDispatcher и используя композицию вызывается метод создающий новое событие. Во всех остальных классах также создаются экземпляры класса унаследованного от EventDispatcher и подписываются на это событие.
Проблема: событие не срабатывает (слушатели не вызываются), никаких ошибок и исключений нет.

Привожу код (код я специально сильно упростил).

Класс события:
Код AS3:

package {
 
        import flash.events.Event;
        import flash.events.EventDispatcher;
 
        public class GameOverEvent extends EventDispatcher{
 
                public static const GAME_OVER:String = "gameOver";
 
                public function GameOverEvent(){
 
                }
 
                internal function gameOverListener():void{
                        dispatchEvent(new Event(GameOverEvent.GAME_OVER));
                }
 
        }
}

Код класса создающего экземпляр GameOverEvent и вызывающий метод gameOverListener использую композицию:
Код AS3:

package {
 
        import flash.utils.Timer;
        import flash.events.*;
 
        public class Compozition{
 
                private var timer:Timer;
                private var gameOverEvent:GameOverEvent;
 
                public function Compozition(gameOverEvent){
                        gameOverEvent = new GameOverEvent();
 
                        timer = new Timer(1000);
                        timer.addEventListener(TimerEvent.TIMER, endListener);
                        timer.start();
                }
 
                private function endListener(e:TimerEvent):void{
                        if(timer.currentCount == 10){
                                gameOverEvent.gameOverListener();
                        }
                }
 
        }
}

Код класса подписывающегося на событие GameOverEvent.GAME_OVER:
Код AS3:

package {
 
        import flash.display.Sprite;
        import flash.utils.Timer;
        import flash.events.*;
 
        public class MySprite extends Sprite{
 
                private var timer:Timer;
                private var gameOver:GameOverEvent;
 
                public function MySprite(){
                        this.x = 200;
                        this.y = 300;
 
                        timer = new Timer(1000);
                        timer.addEventListener(TimerEvent.TIMER, moveListener);
                        timer.start();
 
                        gameOver = new GameOverEvent();
                        gameOver.addEventListener(GameOverEvent.GAME_OVER, gameOverListener);
                }
 
                private function moveListener(e:TimerEvent):void{
                        this.x += 5;
                }
 
                private function gameOverListener(e:Event):void{
                        timer.stop();
                        timer.removeEventListener(TimerEvent.TIMER, moveListener);
                        trace("сработало пользовательское событие");
                }
 
        }
}

Подскажите пожалуйста, где может быть ошибка или возможно я вообще ерунду делаю.

caseyryan 19.11.2015 13:06

Вложений: 1
А ничего, что Sprite уже является EventDispatcher'ом? Нужно в документацию заглядывать хоть время от времени ;)
Всю эту конструкцию можно смело удалять, и слать события прямо из персонажа.

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

бакуард 19.11.2015 13:44

Цитата:

А не работает эта конструкция потому, что там каждый раз новый GameOverEvent создается. То есть для каждого экземпляра он свой. Естественно они не смогут слушать события других экземпляров. Если нужно, чтобы эта конструкция работала, объект должен быть один и тот же. Допустим, сделанный синглтоном.
То есть создаем один экземпляр GameOverEvent и просто передаем его в качестве аргумента конструктора того класса, где мы хотим вызывать его методы или подписаться на рассылаемые им события, а там внутри класса "получателя" сохраняем на него ссылку?

И насчет нескольких экземпляров GameOverEvent. У Мука вычитал следующие (как раз он рассказывает как как сделать пользовательское событие "gameOver"):

Цитата:

Любой экземпляр класса Game, создаваемый
классом Console, является получателем пользовательского события "gameOver",
которое возникает после окончания игры.
То есть я так понял можно создать множество экземпляров класса Game (в моем случае GameOverEvent)
и всех их подписать на события создаваемые в классе Game (в моем случае GameOverEvent). Я не совсем понимаю что вы имели ввиду под "То есть для каждого экземпляра он свой", под "он" имеется ввиду создаваемое событие в методе gameOverListener()?

ObOs 19.11.2015 15:47

1)Создавать дополнительный EventDispatcher нет необходимости. EventDispatcher входит в цепочку наследования Sprite(caseyryan вам даже скриншот выложил). Т.е., если ваш герой унаследован от Sprite, он сам может спокойно рассылать события
Код AS3:

hero.dispathEvent(new Event("gameOver"));

2)Почему не работает у вас. Вы рассылаете событие одним экземпляром GameOverEvent, а слушаете(ждете) это событие от другого экземпляра. У вас сейчас что то типа этого:
Код AS3:

                var eventName:String = "someEvent";
 
                var dispatcherA:EventDispatcher = new EventDispatcher();
                var dispatcherB:EventDispatcher = new EventDispatcher();
 
                dispatcherA.addEventListener(eventName, eventHandlerA);
                dispatcherB.addEventListener(eventName, eventHandlerB);
 
                dispatcherA.dispatchEvent(new Event(eventName));
 
 
                private function eventHandlerA(e:Event):void
                {
                        trace("dispatherA");//Этот трейс выполнится
                }
 
                private function eventHandlerB(e:Event):void
                {
                        trace("dispatherB");//А этот не выполнится пока dispatcherB не "плюнет" событие
                }

3)И во тут
Код AS3:

                public function Compozition(gameOverEvent){
                        gameOverEvent = new GameOverEvent();

вы присваиваете переменной переданной в конструктор Compozition новый экземпляр GameOverEvent, т.е. вот тут, по идее, должна выскочить ошибка, т.к. gameOverEvent там будет null
Код AS3:

                private function endListener(e:TimerEvent):void{
                        if(timer.currentCount == 10){
                                gameOverEvent.gameOverListener();
                                //Вот тут ошибка т.к. gameOverEvent==null
                        }
                }


бакуард 19.11.2015 16:15

Спасибо разобрался.

PsychoTech 21.11.2015 09:23

Цитата:

Сообщение от бакуард (Сообщение 1189135)
Спасибо разобрался.

проще говоря достаточно просто создать новый класс Event, и там где ты хочешь чтобы вызывалось это событие пишешь
Код AS3:

this.dispatchEvent(new PlayerAction(PlayerAction.DIE));

конкретнее эту строку нужно писать там где ты проверяешь будет ли вызваться событие или нет к примеру в таймере проверяешь здоровье бойца и как только здоровье упало до нуля или ниже. вещаешь строчку. Вот как я делаю

Код AS3:

//СМЕРТЬ ПРИ здоровье = 0;
                        if ((Characteristics.Health <= 0)&&(this.Died == false)) { //если проверять только здоровье во фрейме или таймере событие будет вызываться с каждым обновлением  а так вызывается только 1 раз.
                                Characteristics.Health = 0;
                                Died = true;
                                dispatchEvent(new PlayerAction(PlayerAction.DIE));
                                trace('игрок умер');
                        }



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

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