00:00
00:00
Newgrounds Background Image Theme

Zombiehit just joined the crew!

We need you on the team, too.

Support Newgrounds and get tons of perks for just $2.99!

Create a Free Account and then..

Become a Supporter!

AS 3: Custom Events

1,214 Views | 4 Replies
New Topic Respond to this Topic

AS 3: Custom Events 2008-09-04 16:46:49


AS 3 Main

I've seen more than one post or reply to a thread about working with events in AS 3. The current AS main tutorial is a little skinny on the details, so this is going into greater depth about how to create and use your own custom events in AS 3.

Custom Events the Easy Way
Before you start worrying about extending the Event class (which I'll cover later), you should always ask yourself this question: Do I need my custom event to hold any information beyond what the Event class already does? You might want an enemy ship to notify a controller object when it's destroyed by the player's fire, for example. The Event class already provides a way to access the object firing the event through its target property, and you probably don't need to carry any extra information in the event. In this case, simply defining a new event type is sufficient. The easiest way to collate a number of new event types into a single place is to use an enumeration; a class that consists of nothing but static constant variables. For example:

public final class GameEvents {
  public static const STAGE_BEGIN:String = "stage_begin";
  public static const STAGE_CLEAR:String = "stage_clear";
  public static const ENEMY_KILLED:String = "enemy_killed";
  public static const PLAYER_KILLED:String = "player_killed";

  function GameEvents() {}
}

The above code creates a simple enumeration of event types appropriate for a side or top-scrolling shooter. Since these are simply new types for the basic Event object, you don't have to do anything special to use them; simply register to listen for your newly defined event types like normal (someMC.addEventListener(GameEvents.ENEM Y_KILLED, updateScore), for example). To create one of your custom event types you once again do nothing special: ev:Event = new Event(GameEvents.PLAYER_KILLED); dispatchEvent(ev) will create a new Event object with the type of PLAYER_KILLED and dispatch it into the event flow.

Note that when you create an enumeration, you still have to declare a constructor function for the class. In addition, unlike AS 2, you cannot declare a class's constructor private. The best you can do is declare it internal (which was done implicitly in the example by leaving the security descriptor out), which means only classes within the same package can see the constructor.

Fully Custom Events
Sometimes, defining new event types for the basic Event object is all the customization you need to handle events in your application. Other times, however, you need your event to carry information above and beyond that which is carried by the normal Event class (consider both the MouseEvent and KeyboardEvent subclasses of Event, each of which carry additional information that the basic Event class does not). When this is the case, your only option is to extend the Event class to create your own custom event. Doing this can be a bit tricky, so we'll take it step by step.

Step 1: Event Types
When you know you need a fully custom event, you'll next need to know what types of events your custom event is going to represent. In the example below, I'll define a custom event class called GFXEvent. I know I want GFXEvent to represent two separate events in the lifetime of a particle or other short-lived graphical effect; a GFXEvent.DEATH event is dispatched when the effect has reached the end of its lifespan and is ready to be removed from the stage. A GFXEvent.SYNC event is dispatched when the effect needs to notify a listener it has reached a certain point so certain actions can be synchronized (ie, clear or change the contents of the stage when a clip of a big black box reaches 100% alpha, obscuring what's going on).

Step 2: Invoke the super Statement
If I had to guess, I'd say fully 90% of all attempts to extend the Event class go down in flames in the constructor of the new event class. This has a lot to do with how Flash handles subclasses and superclasses. In a nutshell, every time the constructor of a subclass is called, the constructor of the superclass is also implicitly called (unless a super statement appears in the constructor). Here's the kicker, the superclass constructor, if called implicitly, is called with the same parameters passed to the subclass's constructor. In the case of the Event class (the superclass of all Event subclasses), the constructor takes the form:

public function Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)

As you can see, if your own event subclass constructor needs, say, another String to properly initialize its extra information, if you allow the Event constructor to be called using the same parameters as that passed to your subclass, the result will be a type mismatch, the superclass will not instantiate correctly, and your new event will not work. You get around this by explicitly calling the superclass constructor with the super statement, and passing parameters to super (which stands in for the superclass constructor) that are acceptable to the Event constructor. Generally speaking, this means you call super(eventType) during your own event's constructor. If this is kind of eye-glazing, bear with me. When you see the example code at the end it will be more clear.

Step 3: Override Methods
The final step in creating your own custom event is to override certain methods of the Event class to make sure that the additional information your own custom event carries is properly copied when the event propagates. For debugging purposes, it's also a good idea to override the toString method of the Event class to make sure your extra information appears there, as well.

In AS 3, you have to use the override keyword to override a function defined by a superclass. When you use override, the new function must have the same name, require the same number and type of parameters and have the same return type as the function being overridden. To ensure your extra information propagates correctly during the event flow, you must override the clone method of the Event class. The exact method of doing so is shown below.

Step 4: Register Listeners and Get Cracking
Once you have properly defined an Event subclass, you can register listeners for it, create and dispatch it like any other type of event. With that, here is a properly defined subclass of the Event class called GFXEvent.

package {
  import flash.events.Event;
  import flash.display.Sprite;

  public class GFXEvent extends Event {
    //Type enumerations
    public static const DEATH:String = "death";
    public static const SYNC:String = "sync";

    public var parentReference:Sprite;

    public function GFXEvent(t:String, r:Sprite) {
      this.parentReference = r;
      super(t); //This call to super passes only the string of the event type to the Event superclass constructor.  This ensures that the superclass will be created correctly.
    }

    public override function clone():Event { //Remember, override functions must match the original declaration EXACTLY!
      return new GFXEvent(this.type, this.parentReference);
    }

    public override function toString():String { //See above
      return formatToString("GFXEvent","type","parentReference","eventPhase");
      /*formatToString is a built-in function of the Event object to help format the toString output.  You pass it a comma-separated list of strings; the first of which must be the class name and the rest being the properties of the event you wish to be output in the string.*/
    }
  }
}

This concludes the overview of using custom events in Flash. If this has raised more questions than answers for you, reply! I'll try to explain whatever you need me to better.

Response to AS 3: Custom Events 2008-09-04 17:06:56


Great post!!


BBS Signature

Response to AS 3: Custom Events 2008-09-04 19:01:53


Great post! But personally I tried using custom events, and really you don't need it.

I mean you can either create custom stuff, register listeners, organise everything... or, you can just call the function directly :P

With other events, you have to use the events, because they happen with something internally that you can't touch. But if it is custom, you can get there.

I can think of some uses though, but personally it's faster to just call things directly :)

Response to AS 3: Custom Events 2008-09-04 22:24:18


I can think of some uses though, but personally it's faster to just call things directly :)

Faster, but not as flexible. For instance, if you want to affect more than one object, you have to call more than one function. An example would be a PAUSE event. If you have fifty events on stage and dispatch a PAUSE event, they all hear it. If you do it with a callback, you have to call fifty functions.


Flash Game Development Blog: { P I X E L W E L D E R S } | Coming soon: OS Wars: Winvasion!

BBS Signature

Response to AS 3: Custom Events 2008-09-04 22:43:30


I personally use events because I'm a lazy bum and I don't like to write more than I have to. To me, the minimal extra effort to extend the Event class is worth the flexibility and reusability it grants me. To take GFXEvent for example, it doesn't matter what type of effect I need to create, I have a simple, portable, standardized way for it to talk to the rest of my project, no matter what needs to listen, how many things need to listen, or if a given object even cares at this moment what that effect is up to. I just can't get that level of flexibility that easiliy with callbacks.