A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 26

Thread: A problem with event dispatcher

  1. #1
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268

    Question A problem with event dispatcher

    Hi all!
    I got a weird problem with event dispatcher . I'm programming a little tank game (Check the attachment). The main class for tank is game.serovkonstantin.tanks.Tank.as and there are also 2 subclasses for now: Abrams and T90 which extend Tank. In my game.serovkonstantin folder I have a custom event (TankEvent), and the only event type inside of it which is TANK_INACTIVE.

    I've added an event listener for MouseEvent.CLICK to each of the tank instances (inside Tank.as) which works just fine. When I add any of the tank instance onto the stage and click it, it traces the tank's name just like I wanted whether it's Abrams or T-90 depending on what tank I clicked. But the problem is that when I click a tank I also want it to dispatch my TankEvent.TANK_INACTIVE. The main stage has a listener for this event, so I expected it to catch the event and trace some phrase, but nothing happens I don't know whether it doesn't dispatch my event or doesn't catch it.

    ========
    if you're interested why I need to dispatch this event, well, I suppose it will help my game know what tank to move when I click somewhere on the stage, and what tank(s) should be inactive, event it they all of the same type. I mean if I click one of the tanks it accepts all the controls while the other should be inactive (I hope it's not too confusing )


    If someone can show me another way to do so, I'd really appreciate it
    Attached Files Attached Files
    Last edited by caseyryan; 06-20-2010 at 02:39 PM.

  2. #2
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    In order to listen to an event it has to be dispatched. So NewWar has to be changed for example to this.
    PHP Code:
    private function initialize(e:Event):void 
            
    {
                
    removeEventListener(Event.ADDED_TO_STAGEinitialize);
                
    addEventListener(TankEvent.TANK_INACTIVEdeactivateTank);
                
    stage.addEventListener(MouseEvent.CLICKmoveTarget);
                
                
    ks_camera = new Camera(this);
                
    ks_abrams = new Abrams(ks_camera, new Point(200300));
                
    ks_t90 = new T90(ks_camera, new Point400300));
            }
            
            private function 
    deactivateTank(e:Event):void 
            
    {
                
    trace("tank is no longer active");
            }
            
            private function 
    moveTarget(e:MouseEvent):void 
            
    {
                
    trace(Globals.targetName);
                
    dispatchEvent(new Event(TankEvent.TANK_INACTIVE));
            } 
    - The right of the People to create Flash movies shall not be infringed. -

  3. #3
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    It works when I dispatch an event from NewWar.as but I don't need it. I need my tank to dispatch this event when it's clicked. And this is where I'm completely confused. It should work the same way, but it doesn't

    Even though the the tank reacts to the MouseEvent.CLICK perfectly.
    Last edited by caseyryan; 06-21-2010 at 09:07 AM.

  4. #4
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    This will also work, when you change from stage to the tanks.
    ks_t90.addEventListener(TankEvent.TANK_INACTIVE, deactivateTank);
    ks_abrams.addEventListener(TankEvent.TANK_INACTIVE , deactivateTank);

    The event when dispatched from the tanks is only received by the tanks but not by the stage.
    - The right of the People to create Flash movies shall not be infringed. -

  5. #5
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    aha, bingo! It works now, thanks!

    But I still can't get why can't stage listen for this event...

  6. #6
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    I think, because the event is dispatched from the superclass and so only objects extending the superclass can listen. however, you can extend the scope to the stage if you change some part in the Tank class:

    var myTimelineisplayObjectContainer = ks_tank.parent.root as DisplayObjectContainer;
    myTimeline.dispatchEvent(new TankEvent(TankEvent.TANK_INACTIVE));

    This is now received by the stage as well.

    The way event dispatching works is a good way to limit the listener to certain objects.
    Last edited by cancerinform; 06-21-2010 at 10:32 AM.
    - The right of the People to create Flash movies shall not be infringed. -

  7. #7
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Events do not care about what dispatchers and listeners extend, except that they must extend EventDispatcher or implement IEventDispatcher. Other than that, the lineage of an object has no bearing on what can listen to its events or what events it can listen to.

    The probable actual reason that only the dispatching tank could hear the event was that the event did not bubble. I haven't seen the actual code, but unless you set the bubbles property to true when you create the event, it will only go to the same object which dispatches it.

  8. #8
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    It's not quite true. The event bubbling was set to true and both classes implemented IEventDispatcher. I have also noticed something similar when using custom events.
    - The right of the People to create Flash movies shall not be infringed. -

  9. #9
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Great. Now I've got to look at the code. Is the fla necessary?

  10. #10
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    And for completion here is a much simpler example, where the bubbles are set to true but the event is only caught by the object dispatching it.
    http://flashscript.biz/test/EventExample.zip
    - The right of the People to create Flash movies shall not be infringed. -

  11. #11
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    Quote Originally Posted by 5TonsOfFlax View Post
    Is the fla necessary?
    Yes. I compile it in Flash CS4.

  12. #12
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Okay, so here's the deal:
    The TANK_INACTIVE event is dispatched from Tank, but the Tank instances are not actually on the displayList, so the events have nowhere to bubble to. Changing the dispatchEvent to be
    Code:
    ks_tank.dispatchEvent(new TankEvent(TankEvent.TANK_INACTIVE));
    makes the MovieClip which actually is on the display dispatch the event, which can then bubble as desired.

    There's a lot in this project which I think could be better designed, but that's partially a personal preference.

  13. #13
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    5TonsOfFlax, I'm just learning it So, if you know the better way to design it, I'd really like to know about that.
    I don't have an established personal preference yet

    The TANK_INACTIVE event is dispatched from Tank, but the Tank instances are not actually on the displayList, so the events have nowhere to bubble to.
    So, invoking the super class Tank thru it's children is not the same as invoking it directly?
    Last edited by caseyryan; 06-21-2010 at 11:43 AM.

  14. #14
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    5Tons, what you are saying is not completely true. If you look at my example, which I linked, not all objects (Displayobjects) can listen.
    - The right of the People to create Flash movies shall not be infringed. -

  15. #15
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    There's actually a lot to like about the way you've put things together, but there are also a few things which can cause some trouble. The first is that your Tank extends MovieClip, but is never actually put on the display. This indicates to me that you've got a bit of confusion regarding what exactly each of your classes does. For instance, you're setting mouseChildren and buttonMode in Tank, but since you never see a tank on the display, these are useless. Also, you explicitly say that Tank implements IEventDispatcher, but since MovieClip already does, that's unnecessary.

    Anyway. I'd suggest either being very clear about what is a "logical" class and what is a "display" class, or just actually using your Tanks as display objects. Which brings me to the next point.

    I don't think it's a good idea for objects to be passed a parent in the constructor and put themselves on the display. In this case, you are actually putting a graphic asset on the display and NOT the Tank itself. I'd forget the parent parameter, and just have the Tanks set themselves up. Add the graphics to the Tank subclass instance itself, then add the Tank instance in the place where you create the tank. This would also remove the need to pass the location parameter, since the code which creates the Tank can also position it.

    I'm not sure that making your events default to bubble = true is a good idea, but this one does seem like personal preference more than anything. The only reason I have an opinion is that the Event base class does have a default for the bubbles parameter, which is false. Without knowing your code, seeing a new TankEvent without a bubbles parameter would look like that was a non-bubbling event.

    I think Globals are generally a bad idea. Pass values up through function returns, or event targets, or even data fields in events.
    If you DO want to continue using Globals, at least store the information you really want. Do you really want to know the name of the target? Or would you rather have a reference to the target itself?

    Before adding a listener to the stage, strongly consider whether that listener should be on the document class or other container instead. In this case, I think the click listener should be on the stage if you need to click blank areas. The TANK_INACTIVE listener could be on the document class instance.

    Consider in general the proper classes to extend. If a class does not need frames or frame script, it should not be a MovieClip.

    cancerinform, I don't have flash here so I can't compile your example as is. I replaced the List with a Sprite so I could compile it. When I click the sprite, the onListItemClick function executes as expected. I'm not sure what that was supposed to illustrate.

  16. #16
    Mod cancerinform's Avatar
    Join Date
    Mar 2002
    Location
    press the picture...
    Posts
    13,449
    The Receiver object cannot listen to the event. Therefore as shown in the script I have to have a reference to the stage or Documentclass. Listening would be bubbling down. So in other words there are certain limits. Also I think it is not a good idea to set the bubbles to true, since the objects, which can listen are not as much limited as if bubbling is false. But that is a different issue.
    PHP Code:
    public function Receiver (myClip:DisplayObjectContainer):void
            
    {
                
    myText = new TextField();
                
    addChild (myText);
                
    myClip.addEventListener (ListItemClickEvent.LIST_ITEM_CLICKonListItemClick);
            }
            private function 
    onListItemClick (evt:ListItemClickEvent):void
            
    {
                var 
    obj:Object evt.data;
                
    myText.text String(obj);
            } 
    myClip here is a reference to the Document class.
    - The right of the People to create Flash movies shall not be infringed. -

  17. #17
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Oh. We are talking across each other then. Yes, obviously Reciever cannot recieve events via bubbling from its parent. Bubbles only go up. Except in Guinness.

    My point was that Reciever can in fact listen to its parent as you've shown there, just not via bubbling. It has to add the listener to the parent directly.

    I've mentioned an EventManager pattern here before which allows you to emulate a global broadcast pattern. The idea is that you have a singleton broadcaster instance, and all dispatchEvent and addListener calls for broadcast events are done on that instance. But that's neither here nor there.

  18. #18
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    The first is that your Tank extends MovieClip, but is never actually put on the display. This indicates to me that you've got a bit of confusion regarding what exactly each of your classes does. For instance, you're setting mouseChildren and buttonMode in Tank, but since you never see a tank on the display, these are useless
    Yeah, sometimes I really get a bit confused about what to use, sprite or moviclip

    Also, you explicitly say that Tank implements IEventDispatcher, but since MovieClip already does, that's unnecessary.
    Does it? When I first created it, it only extended MovieClip but this gave me a lot of errors when I tried to dispatch any event from it, but after I implemented an IEventDispatcher to it, it worked out fine

    I don't think it's a good idea for objects to be passed a parent in the constructor and put themselves on the display. In this case, you are actually putting a graphic asset on the display and NOT the Tank itself. I'd forget the parent parameter, and just have the Tanks set themselves up. Add the graphics to the Tank subclass instance itself, then add the Tank instance in the place where you create the tank. This would also remove the need to pass the location parameter, since the code which creates the Tank can also position it.
    I tried to do it both ways. The same result but less lines of code.

    I'm not sure that making your events default to bubble = true is a good idea
    I tried it set to false, it didn't work, then I changed it to true, didn't work either

    If you DO want to continue using Globals, at least store the information you really want. Do you really want to know the name of the target?
    At this point, not. But when I add a UI I'll need it, because the target returns something like "instance3" instead of the name of the tank that I clicked, and if I use Global variable to store the name, it works just fine.


    Also I think it is not a good idea to set the bubbles to true, since the objects, which can listen are not as much limited as if bubbling is false.
    I never try to set any of them to true it everything works like I planned

  19. #19
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Quote Originally Posted by caseyryan View Post
    At this point, not. But when I add a UI I'll need it, because the target returns something like "instance3" instead of the name of the tank that I clicked, and if I use Global variable to store the name, it works just fine.
    That's because the target is the graphic instance which you added to the logical instance. The graphic instance doesn't have a name, because you never gave it one. Names aren't that useful anyway.

    If you make it so that the Tanks are actually on the display, and set mouseChildren appropriately on them (false), they will dispatch the click events, and will be the targets.

  20. #20
    Senior Member
    Join Date
    May 2010
    Location
    Russia: Western Siberia
    Posts
    268
    There's also a little problem with this way. If I add the tanks as you say and click the edge of any of them it will work like it's supposed to, but the trick is that each tank movieclip has another movieclip inside, which is called mTurret. So if I click the turret area it returns the name "mTurret" no matter if I set it's mouseChildren property to false or true

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center