How to Raise Custom Events (AsBroadcaster)

ActionScript 2.0

Just the other day, we looked at the difference between event handlers and event listeners.  That article discussed handling events raised by built-in ActionScript classes, such as Button and MovieClipLoader.  So, what if you want to generate your own custom events?  ActionScript certainly supports the practice, and there are two out-of-the-box ways to do it.  But let’s pause for a moment.  Frankly, why would a person even want to raise custom events? 

Backstory

In my own experience, I find it a matter of great convenience.  One of my freelance gigs last year required a game in which the user pilots a boat among “good” objects (beach balls, buoys) and “bad” objects (crocs, squid) while racing against time to the opposite shore.  Well, there is no onCollide event in any native ActionScript class, so I had to either repeatedly check for collisions — looping with, say, MovieClip.onEnterFrame or setInterval() — or define my own onCollide event and use that.  Going with the event approach meant I could simply subscribe any object as a listener to my boat object and act accordingly, rather than keep track of perhaps dozens of “Is there a collision yet?” loops.

As you can imagine, I’m greatly over-simplifying this project.  To be sure, there was plenty of looping going on.  The important thing was that I compartmentalized my lines of attack, which is one of my favorite aspects of object-oriented programming.  I wrote a Boat class, for example, and also an Obstacle base class, which I extended with a Friend and Foe class, and so on.  I took this approach in order to neatly organize various basic game concepts (boats, friends, foes) into self-contained objects that were easy to work with.  In the Boat class, I included a mechanism that detects collisions and raises a Boat.onCollide event as necessary.  This event carries with it a number of properties, including what objects are involved in the collision (friend, foe, shore, edge of Stage).

Note:  It is not necessary to write your own classes in order to raise custom events.  Class writing merits its own article, for sure.  (If you’re interested in learning it right now, I heartily recommend Joey Lott’s three-part “ActionScript 2.0 Primer.”  We’ll continue here with an example that simply uses a generic Object instance.)

In handling your own events, you’ll use the event listener model, rather than the event handler model.  This works the same for custom events as it does for native events; that is, a generic Object instance acts as liaison between the event raiser and the event listener.  We’ll start with the AsBroadcaster class; I’ll follow in another article with the EventDispatcher class.

An answer, relatively short and sweet

To employ AsBroadcaster, it’s necessary to produce two generic Object instances:  one object that broadcasts and another that listens.  If this already has you seeing spots before your eyes, read the previous event handler/listener article, because this builds on the concept introduced there — it’s honestly just one step further.

var broadcaster:Object = new Object();
AsBroadcaster.initialize(broadcaster);

In the above two lines, an arbitrarily named variable, broadcaster, stores a reference to an instance of the Object class.  The static AsBroadcaster.initialize() method converts broadcaster into a bona fide broadcasting object.

var listener:Object = new Object();

Next, another arbitrarily named variable, listener, stores a reference to our second Object instance.  At this point, we proceed along already familiar lines; namely, assigning functions to events of our “liaison” listener object.  The events are custom, and you’ll see in a moment how they’re defined.  They notify the listener object that something has been picked up and also that something has been dropped.  In the dropped notification, the event specifies where the dropping occurred.

listener.onPickedUp = function() {
  trace("Picked up.");
};
listener.onDropped = function(msg:String) {
  trace("Dropped on " + msg + " side.");
};

Finally, we invoke the AsBroadcaster.addListener() method on the broadcaster object.  This subscribes listener to broadcaster.

broadcaster.addListener(listener);

This process is virtually identical to subscribing listeners to MovieClipLoader (or any other built-in class instance that broadcasts).  The only thing remaining is to define the onPickedUp and onDropped events.

The AsBroadcaster.broadcastMessage() method gives us what we need:  invoke this method on the broadcaster object and, at minimum, pass in the custom event as a parameter.  For starters, the onPickedUp event:  in this one, we only care that an event has occurred, so the custom event name is passed in as a string.

broadcaster.broadcastMessage("onPickedUp");

In the onDropped event, we also care about where the dropping has occurred, so an additional parameter is supplied — happens to also be a string.  We could supply any number of parameters as any valid data type, by the way, but we’re just looking at one.

broadcaster.broadcastMessage("onDropped", "left");

For a practical example, download AsBroadcaster.fla (opens as far back as Flash MX 2004).  In the FLA file, you’ll find a draggable “ball” movie clip.  Its draggability is due to functions assigned to the MovieClip.onPress and MovieClip.onRelease events.  Note that these functions also invoke the AsBroadcaster.broadcastMessage() method.

var halfway:Number = Stage.width / 2;
mcBall.onPress = function() {
  this.startDrag();
  broadcaster.broadcastMessage("onPickedUp");
};
mcBall.onRelease = function() {
  this.stopDrag();
  if (this._x < halfway) {
    broadcaster.broadcastMessage("onDropped", "left");
  } else {
    broadcaster.broadcastMessage("onDropped", "right");
  }
};

23 Responses to “How to Raise Custom Events (AsBroadcaster)”

  1. sdudu Says:

    Ok, but what if the the event to be bradcast comes from a object inside a movieclip loaded (via Moviecliploader). let me detail my inquire :

    - I have a Main.fla, that creates a Main.as class, with a HelloWorld() method.
    - this Main.as class load in a emptymovieclip a external clip (via a movieclipload), banner.swf
    - this banner, based on the banner.fla file, instancies a banner.as class.

    And now, imagine that this banner.as class build the banner.swf content, with several attachmovies (symboles are in the banner.swf). Of course, events are dynamically attached to those “symbol”. One of them should broadcast a event that concerns the main.as class (for instance, the ask for the execution of the Main.Helloworld() method)

    No way. I’ve never find a proper solution to this problem, but by a explicit call to _root.Main.Helloworld().

    Is there not another way ??

  2. David Stiller Says:

    sdudu,

    Makes no difference what object makes the broadcast. Even external SWFs, once loaded, are part of the outermost parent document — it’s all part of the same application. I suspect your issue is a matter of timing. You can’t subscribe to events broadcast by an object that doesn’t yet exist. When your banner.swf is loaded, you should subscribe Main’s listeners after banner’s broadcasters are instantiated.

    Does that make sense?

  3. Rupert Ong Says:

    I was wondering if you could help me out. I want to use AsBroadcaster in an external .as file.

    Here’s the situation. I want all the instances of a custom class to execute a certain function when told to. My reasoning in using AsBroadcaster was to initialize a static broadcaster object, which would add the instances of the class as listeners every time a new instance was created. I would then call a static function which would make all the instances execute their function.

    Here’s my code in the Testing.as file:

    class Testing {

    private static var broadcaster:Object = new Object();
    private var customMessage:String;

    function Testing(pMessage:String) {
    AsBroadcaster.initialize(broadcaster);
    broadcaster.addListener(this);
    customMessage = pMessage;
    }

    function onTalk():Void {
    trace (customMessage);
    }

    public static function allTalk():Void {
    broadcaster.broadcastMessage(”onTalk”);
    }
    }

    =============================

    And here’s the code in the Flash file:

    var classA:Testing = new Testing(”hello”);
    var classB:Testing = new Testing(”pickles”);
    var classC:Testing = new Testing (”bye”);

    Testing.allTalk();

    =============================

    Currently, only the last class instance executes its function. Is there any way to get all the instances to do so?

    Thanks!

  4. David Stiller Says:

    Rupert,

    I’m unclear on why you’re employing AsBroadcaster here. If your intent is to invoke a static method by hand, why the broadcast? It may be that I simply don’t follow your endeavor. I think you wish to tell all Testing instances, in one swoop, to trace a non-static message. If that’s it, you’ll find you cannot access instance variables from a static function.

    Can you rephrase what you’re after?

  5. Rupert Ong Says:

    Thanks for the reply David.

    The example I placed in my previous post was a simplified version of what I’m after. Sorry for the confusion.

    Essentially what I have is several instances of a class I’ve called SwapPhoto on the stage. I’ve programmed each instance to be draggable, and when they are released over a certain “target” movieclip, they disappear and execute its designated function.

    Now here’s my problem.

    If I drag and release another instance of SwapPhoto over the “target” movieclip, it too will disappear and execute its designated function. That’s fine, but what I need is to have the previously dragged and dropped instance to reappear and move back to its original position.

    I was thinking of trying to have all the instances of the SwapPhoto class to execute a method defined in the class called reset(), which would make it reappear and snap back to its original position if it was previously invisible.

    Am I going about this the wrong way? It seems like a simple enough process, but I can’t seem to get it working correctly for some reason.

    Any help would be much appreciated. Thanks David, and sorry for the stupid questions!

  6. David Stiller Says:

    Rupert,

    I don’t think your questions are stupid. Thanks for leaving feedback. :)

    Generally speaking, there are half a dozen ways to approach any ActionScript problem, and probably half a dozen more ways to solve it. (All right, maybe I exaggerate, but you get my drift.) ;) In a situation like yours, custom events might make sense. I could see raising an event if you wanted all instances of SwapPhoto to shimmer, shudder, or perform some other visual effect when any one of them was dragged to the target. Signaling a reset, however, may be something of an overkill, especially when only one of them needs to perform the instruction. Sure, you could have each SwapPhoto instance check, before performing a reset method, to see if it’s already at its beginning position. But why have each perform unnecessary processing?

    In this case, I would write a second class just for the target — give the target a property that stores a reference to whatever SwapPhoto instance was last dragged into it. The first time it happens, the target will see that this property is null and simply note a reference to the current SwapPhoto instance. Next time, it can invoke SwapPhoto.reset() specifically on that instance, and then swap out that reference for the new one.

    Does that make sense?

    Part of the problem with your original example is that you’re asking each class instance to reference a static property from an instance method. The compiler just isn’t going to like that.

  7. MooDy Says:

    Very Usefull information David …
    keep up the good posts ;)

    m0o

  8. David Stiller Says:

    Thanks MooDy!

  9. maharaja Says:

    hi David,
    thanks for the knowledge… but i have one doubt
    i am not still clear abt the use of the customized listener .. as we can acheive same thing by calling function (as in asbroadcaster.fla)
    i know u have given the simplest code for understanding & i really appreciate for that, but i am still unclear that in what circumstances does listener help out

    please bear with my doubt as i am new to listener & i use it very rarely(those in-built type) so i am unaware of the power that listener provide to us.. pls pls clear my doubt

  10. David Stiller Says:

    maharaja,

    A more complex example may be found in the two-part “Loading and Tracking Multiple Files at the Same Time“; in particular, you’ll find a custom event dispatched in part two, but it makes sense to start the pair of articles from the beginning.

  11. nick Says:

    I am having an issue with the use of AsBroadcaster and can’t quite figure out the issue. I have a container SWF (the main one) that initializes the AsBroadcaster object and also creates/adds the custom listener objects to the broadcaster. Then I load an external SWF into that container which is the one that actually does the broadcasting.

    Now, this works if the two SWFs come from the same domain. However, I really need them to come from two different domains which then prevents the broadcasted events of the loaded SWF from reaching the main container with the listener objects. I understand Flash’s security and cross domain scripting functionality, so both SWFs have System.security.allowDomain(”*”); in their AS to allow any domain to access each other. I know that the two SWFs can now access one another since I can call methods on each other, but for some reason AsBroadcaster still does not work.

    Are there security issues similar to LocalConnection that would prevent AsBroadcaster from working between SWFs from different domains?

  12. nick Says:

    Nevermind my previous post… I found the issue was the global scope of variables across different domains and not the AsBroadcaster object iteself. Doh! :)

  13. Andy Says:

    Hello David,

    Thanks for the article.
    Something that I’m unclear about is how do you write a custom condition for when the broadcaster broadcasts the event?

    I have a situation in which I have an animation where I would like a movieclip to broadcast when it is at a certain _y position so that another function may run.

    How do I use your example to write a condition for when the event is broadcast?

    Thanks,

  14. David Stiller Says:

    Andy,

    You’ve got two choices, here. You can either broadcast the event any old time, and let the receiving object determine whether or not it cares (use if in the listener) — or you can broadcast the event only when a particular condition is met, which is what you’re leaning toward, it sounds like.

    In the article itself, I programmed the event to be dispatched in response to an onRelease event, and then dependent on an if statement. In your case, you might use an onEnterFrame event (or maybe setInterval()) to repeatedly check the _y position of your movie clip. Inside that loop, use an if statement of your own to evaluate the value of _y.

  15. Andy Says:

    Hi David,

    Thank you for the reply. As in your article, I’m trying to avoid using any sort of frame loop. I am currently using an onEnterFrame loop to check the _y of the MC.

    Is there a way to code a custom condition to broadcast a custom event without any sort of user input?

    Thanks again,

  16. David Stiller Says:

    Andy,

    If you don’t want to use onEnterFrame to check, you could certainly use setInterval() — but heck, if you’re already employing a loop, put it to work for you! ;)

    I don’t mean to suggest that loops are essentially bad things — I hope the article doesn’t push that point too strongly — but in this case, if the _y position isn’t dependent on user interaction, you’ve got to check for it somehow, and presumably repeatedly.

    Custom events can be broadcast whenever you please; that’s the benefit they bring to the table. In the article above, the dispatch occurs based on an onRelease event, which happens to be user-dependent. But the choice is yours. You’re already checking the _y position, apparently on a recurring basis (frame loop), so as you do so, dispatch an event when _y hits the magic spot.

  17. Andy Says:

    Hi David,

    Perhaps I’m not understanding the broadcast-listener model correctly.
    I thought that I might be able to get ASBroadcaster to check for _y and through writing a custom event (ie: _y == 150) broadcast the magic moment so that another MC I want to register as a listener will then start a function.

    With the frameloop, I have to place a switch statement within it to check for a variable I toggle so that the frameloop doesn’t continuely call the function I want to run only once. This doesn’t strike me as very elegant but it works.
    This particular situation is fine as it only involves two MCs but I think this method wouldn’t work very well if I had multiple MCs with conditions to check as was the case with your game example.

    I thought if I could use ASBroadcaster or DispatchEvent to check for a recurring specific condition and broadcast accordingly that it could eliminate the need for frameloops entirely.

    Thanks again for your responses,

  18. David Stiller Says:

    Andy,

    If you have a sense of confusion in this particular context, the likeliest bet is that I failed to write the above blog entry as clearly as I could or should have. I think you’re asking me, “I’d prefer not to have so many loops. Loops, in this case, are based on the onEnterFrame event, and I don’t want to use that event — I’d like to dispatch an event of my own.” Conceptually, that makes sense to me.

    You certainly can generate a completely custom event, and you can generate it whenever you like. You’re saying the event should be dispatched every time a certain movie clip’s _y property hits a certain value. Practically speaking, the only way your code will know when this value has been attained is to check that _y property repeatedly. If you’re animating that clip programmatically, then you presumably already have a looping mechanism in place. By using that mechanism to dispatch your event, you can avoid having a second loop that checks the _y position for you.

    If you’re not using ActionScript to animate that clip, then you may be able to dispatch your event from whatever keyframe represents the _y position you’re after.

    But the problem here may simply be the examples I alluded to in the blog entry itself. See “Loading and Tracking Multiple Files at the Same Time (Part 2)” for an example that may make more sense. :)

  19. Andy Says:

    Hi David,

    Thanks again for your response.
    I thought your article was well written. It got me thinking and this isn’t the first time I’ve tried to get software to do something that it maybe can’t do.
    I’ve always used frameloops. But they aren’t very elegant for checking on multiple conditions. I have used setInterval but I find that they can also be a dangerous situation when using multiple intervals.

    Why I feel I don’t understand the broadcaster/listener concept is that I’m expecting to be able to write a custom event such as (mc1._y == 150) and have ASBroadcaster take the place of the frameloop.

    In my understanding, if I add a custom event to ASBroadcaster, I would like to see ASBroadcaster watch for my custom event whenever it occurs. (Just as it will sit and wait for a mouse click). When it does occur, it would broadcast that it has occurred to any registered listeners (mc2) to run a function a single time.

    I’m not certain this can be done but I appreciate your thoughts on this.
    It’s a long weekend here in Canada so I won’t have to worry for a few days about making pixels fly.

    Thanks again,

  20. David Stiller Says:

    Andy,

    Thanks. :) I hear what you’re saying. The closest you’re going to get — and unfortunately, it won’t work in this case — is the Object.watch() method. That “keeps an eye on” object properties and lets you know when they’ve changed, but it doesn’t work for the properties like _y, and the documentation goes into a brief bit of detail about that.

    With regard to ASBroadcaster and EventDispatcher, you can indeed listen for events on an as-they-occur basis, it’s just that from a programming perspective, part of that scenario involves actually dispatching the event, and only your programming will know when/how to do that. In some circumstances, Object.watch() would allow you to dispatch the event; in others, it may take a loop; in yet others, user input, and so forth.

  21. Random » Blog Archive » Creating Custom Events in Flash Says:

    […] I read about it here and here. […]

  22. Dameon Says:

    Yeah I was wondering the same thing as Andy. My problem is more around the ._alpha property. I’m one of those Flashies who HATES websites that dont use perfect animation. So of course I have OnEnterFrame loops being turned on and off all over the place. I was thinking there may be a way to clean up my code and use events and listeners instead of creating frame loops with conditional statements in them.

    However this article gave me some good new ideas not related to that issue.

  23. David Stiller Says:

    Dameon,

    You might be interested in the OnEnterFrameBeacon class, then. Check it out on Darron Schall’s “A hidden gem… or two” blog entry. Pretty neat stuff!

Leave a Reply