0

I read a lot of topics about dispatching event but I can't make my code work. This topic and this topic are closed to what I would like to do, but it's not working in my case.

Here is the situation :

  • My scene is a battle field and has two ships
  • Each ship knows when it is touched by a fire, so it has to inform the scene that contains the graphic interface
  • So the ship dispatch a custom event with itself as parameter, so the scene knows when a ship is touched and which ship

I have 3 classes :

  1. The custom event class is an event that has a property "Ship"
  2. The EventDispatcher class
  3. The symbole class that corresponds to my scene and listen to the event

1) CustomEvent class

public class FightEvent extends Event
    {
        public static const SHIP_TOUCHED:String = "SHIP_TOUCHED"; //type
        public var object:Ship = null; //object to pass

        public function FightEvent(type:String, pObject:Ship, bubbles:Boolean=true, cancelable:Boolean=false)
        {
            super(type, bubbles, cancelable);
            object = pObject;
        }

        public override function clone():Event
        {
            return new FightEvent(type, object, bubbles, cancelable);
        }
    }

2) EventDispatcher

public class Ship extends EventDispatcher
{
    private function updateDamages():void
    {
        //compute damages
        dispatchEvent( new FightEvent( FightEvent.SHIP_TOUCHED, this ) );
    }
}

3) Scene

public class Fight extends customMovieClip
{
    private var playerShip:Ship; //I have two ships, player and enemy
    private var enemyShip:Ship;

    public function init():void
    {
         stage.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
         //I made a test : the event listener is correctly added
    }

    private function onShipTouched(e:FightEvent):void
    {
        //update the graphic interface to show damages
    }
}

My event listener is added, the code passes on the dispatch line, but onShipTouched is not called.

Please help, what did I miss ?

What is the element I didn't understand ?

Is it a good way to use events like this ? or should I set a reference to the scene inside the Ship class ?

Community
  • 1
  • 1
Tari-Green
  • 11
  • 3
  • 1
    You need to add the eventlistener to the object that is dispatching the event, that is, one of your ships. the stage is not dispatching the event, the Class `Ship` does that. –  Nov 13 '14 at 12:20
  • Most likely you are changing frames between `addEventListener` and `dispatchEvent`, or probably even scenes, thus the `stage` is different at the time of attaching the listener and the time when the event is fired, so the event reaches **wrong** stage and is dropped with no reaction. – Vesper Nov 13 '14 at 12:37
  • ship is not a displayobject so stage can't magically catch those events. btw this: "public var object:Ship = null;" and this "public var object:Ship;" give ship the same value: null. Since ship is not a displayobject only ship object can listen to their own dispatch. – BotMaster Nov 13 '14 at 13:26
  • @DodgerThud "You need to add the eventlistener to the object that is dispatching the event". I don't understand this, why would I need an eventlistener on the dispatcher that already know what is happening to itself ? – Tari-Green Nov 13 '14 at 13:53
  • @Vesper I am not sure if I understand, do you mean that the onEnterFrame method could be a source of problem here ? I have a KeyboardEvent listener added to the stage (in my class Fight), and it works perfectly. I don't really get the difference between the way the keyboard event is handled and the way my fight event is handled. – Tari-Green Nov 13 '14 at 13:58
  • You misunderstand, in your `Fight` class, you should add the event listener to one of the `Ship` Objects. instead of `stage.addEventListener(...)` do `playerShip.addEventListener(...)` instead. –  Nov 13 '14 at 13:58
  • Hmm, no, this is not the case if you have a working keyboard event listener. Then, check if the event is properly dispatched and bubbled by adding event listeners to both ships and `Fight` instance. If both correctly react to when you dispatch the event, that is, you see traces generated by listeners, then stick to listening on `Fight` level. If not, there's something that either prevents the event from dispatching, or bubbling. – Vesper Nov 13 '14 at 14:03
  • Also, I don't understand why do you need `this` as parameter in the event. I'd understand if there would be a custom data-filled object, or even an integer, but `this` is already present in the `Event` data structure at the field named `target`. – Vesper Nov 13 '14 at 14:04
  • @BotMaster "ship is not a displayobject so stage can't magically catch those events." Ok, so if I take the example of MouseEvent.CLICK, the clicked displayObject has the listener is this what all of you mean ? but where is the dispatch in that example ? (Thank you for all the answers, I am going to read a bit more doc about what you said) – Tari-Green Nov 13 '14 at 14:07
  • Great ! That was it, I understood my misunderstanding. The ships have the listeners that are added in the class Fight. So I don't even need the parameter in the event, the scene knows which ship is concerned because it's the target of the event.Thank you ! – Tari-Green Nov 13 '14 at 14:25

2 Answers2

0

Your Ship class is not a MovieClip, Sprite or their subclass in order for your event to bubble up the display list, just because they don't participate in a display list. So, you change your Ship to Sprite subclass (this one already inherits EventDispatcher), add graphics and addChild() both ships to the stage, this way your stage will receive events properly.

Vesper
  • 18,599
  • 6
  • 39
  • 61
  • An object doesn't have to be a displayobject in order to work correctly with the event system. Your answer kind of imply that all objects should be displayobject and added to the display list just so that the stage can catch those events. That would be a terrible way to code a project. – BotMaster Nov 13 '14 at 14:35
  • @BotMaster See, I agree that this approach isn't correct in this case, but I mean that in order for the event to **bubble** up to stage, the object that dispatches this event should be on the display list. Apparently this is not the case in OP's code. – Vesper Nov 13 '14 at 14:37
0

My logic was wrong :

I was doing this : the eventdispatcher is dispatching the event, and the stage is listening to the event. That is incorrect.

The right solution is : the eventdispatcher is dispatching the event, and is also listening to its own dispatched event. The eventlistener is added to the eventdispatcher in the scene, that contains the function to call.

As Vesper said, the parameter in FightEvent is useless, as the eventdispatcher is actually the event target.

DodgerThud, BotMaster, you gave me this answer, thank you for your help (Looks like I can't set a comment as "answer accepted").

Here the right code for the Fight class :

public class Fight extends customMovieClip
{
    private var playerShip:Ship; //I have two ships, player and enemy
    private var enemyShip:Ship;

    public function init():void
    {
        enemyShip.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
        playerShip.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
    }

    private function onShipTouched(e:FightEvent):void
    {
        //e.target == the ship that dispatched the event
    }
}
Tari-Green
  • 11
  • 3