Events are an important concept in AS3, but can be confusing to anyone that hasn’t come across them in other languages before. This post explains what an event and an event listener is, how to use them, and why they are useful for Flash game development.
Put simply, an object can trigger a function when certain conditions are met, by creating a special kind of object called an Event. Let’s look at a concrete example.
An instance of the Timer class will dispatch an event every time it “ticks”:
We can use an *event listener* to detect these events…
…and trigger a function:
Code for this situation would look like this:
exampleTimer:Timer = new Timer( 1000 ); // 1000ms == 1second
exampleTimer.start();
exampleTimer.addEventListener( TimerEvent.TIMER, onTimerTick );
The first two lines simply set up the timer; it already contains the code to fire off an event every time it ticks.
Line 3 adds an event listener to the timer. As you can see, it is told not just the class of event but also the type of event to listen out for. (The classes and types of events for built-in classes and components are all listed in the AS3 LiveDocs.) It’s also told which function to run when this event is detected: in this case, the function is called onTimerTick(). Such a function is called an *event handler*, and programmers typically name them onSomethingSomething — onMousePress, onPlayersDeath, onFileLoaded.
The event object that the listener detects often contains more information than just what type of event it is. For example, KeyboardEvents store the a number (called a *KeyCode*) referring to the key that a user presses, and MouseEvents store the position of the mouse when it is clicked. The listener doesn’t just *run* the handler, it passes the entire event object (and all its internal data) to it as a parameter.
So event handlers always take this form:
public function onEventOccured( eventObject:Event )
{
//do something
}
Nothing, not even the listener calling the handler, pays any attention to any value that the handler might return. Therefore, all handlers have a return type of *void*.
Our handler for this TimerEvent would look like this:
public function onTimerTick( timerEvent:TimerEvent ):void
{
//do something
}
Note that here I’ve specified that the class of the event being passed through is TimerEvent. Since all events extend the base Event class, you could specify this class as Event without causing any problems, but you wouldn’t be able to retrieve any information specific to that class of event (like *keyCode* for a KeyboardEvent).
You access the data as you would a property of any other object: using dot notation.
public function onKeyPressed( keyboardEvent:KeyboardEvent ):void
{
trace( "The key pressed was: ", keyboardEvent.keyCode );
}
To remove an event listener from an object (and therefore stop it triggering the handler), simply call *removeEventListener* with the same parameters that you used to add it:
exampleTimer.removeEventListener( TimerEvent.TIMER, onTimerTick );
You can add and remove event listeners from within event handlers, too — even removing the listener that triggered the handler, if you like.
On top of that, it’s possible (and easy) to add multiple listeners to a single event:
exampleTimer.addEventListener( TimerEvent.TIMER, onTimerTick );
exampleTimer.addEventListener( TimerEvent.TIMER, onTimerTickWhilePlayerIsAlive );
exampleTimer.addEventListener( TimerEvent.TIMER, onTimerTickWhilePlayerIsHoldingTheSword );
In the above example, you could set up the listeners to trigger different handlers depending on the state of the game, and remove those listeners as the state changed, rather than having a complicated if-then-else block within the handler itself.
Similarly, you can reuse the same handler for different events:
menuTimer.addEventListener( TimerEvent.TIMER, onAnyTimerTickOrFinish );
menuTimer.addEventListener( TimerEvent.TIMER_COMPLETE, onAnyTimerTickOrFinish );
gameTimer.addEventListener( TimerEvent.TIMER, onAnyTimerTickOrFinish );
gameTimer.addEventListener( TimerEvent.TIMER_COMPLETE, onAnyTimerTickOrFinish );
Here, the events have different types and are dispatched by different objects, but they all still trigger the same handler. Remember, though, that the handler is expecting the passed event to be of a certain class, so you can’t use the same function as a handler for both TimerEvents and MouseEvents unless its parameter is only expecting the base Event class.
{ 35 comments… read them below or add one }
Good tips 🙂 Thanks
mind explaining why some could do this?
exampleTimer.addEventListener(“timer”,onTimerTick);
Good question, Ellison.
It’s because TimerEvent.TIMER is actually a const (which is basically a variable that can only be changed at programming time, not once the Flash has been compiled) that is equal to “timer”.
We tend to use TimerEvent.TIMER rather than “timer” for two reasons:
Hope that helps
I did a post on Tip and Tricks for event listeners this might help everyone
http://www.almogdesign.net/blog/actionscript-3-event-listeners-tips-tricks/
Ooh, nice post! Thanks, Almog 🙂
This post made event listeners much easier to grasp. 🙂
very well explained.
thanks
Cheers, Nils and Nirbhay 🙂
I have a .fla template that I use to remove a video layer once the transparent greeter has played through. It was written is AS2. Thanks to the ease of dragging player controls onto the stage in AS3 I would like to replace this stop listener with identical AS3 code. I’m a virtual beginner with Flash CS3 and to date haven’t been able to accomplish it. This is the AS2 code:
A commonjs.js file reacts to the stop and removes the layer. I don’t know enough to know whether or not you’d need to see that to be sure of the same result, but I doubt it. If you can help in any way I’d be grateful.
David in Toronto
Hey David,
Your code looks like it would almost work in AS3 as it is! Let’s see… are you coding on the timeline or using AS files? Also, what exactly triggers the “stopped” event?
Hi Michael,
Thanks for the post; I’m just trying to come to grips with events in AS3. One problem I am facing is knowing when an event / eventhandler has been trigged inside of a class.
ie. this class performs some actions and once all external data is loaded, triggers an event
DatabaseConnection .as
Then in the main class I need to know when completeHandler has been triggered
Main .as
Any thoughts on how this can be achieved?
Cheers
Ryan
Hey Ryan,
You can do this by making DatabaseConnection dispatch an event of its own. You can create your own event class, but it’s probably easier if you clone the COMPLETE event that loader fires off:
You can then add an event listener to your DatabaseConnection object for the COMPLETE event, and have the handler do whatever you want it to do. That should work.
…except it won’t, because DatabaseConnection doesn’t have the ability to dispatch events. The easiest way to get around this is to make it
extend EventDispatcher
(you’ll also need to import flash.events.EventDispatcher).It’s not a perfect solution in all cases (you might want DatabaseConnection to extend something else, for example), but I think it’ll work here 🙂
Hey Michael, I apologize for disappearing after posting my question on stopListeners in AS3. To your question I’m coding on the timeline and it is the end of the video (FLVPB) that triggers the “stopped” event. For reference we’re going back to January 26th in this thread.
David
Thanks for the reply Michael.
I couldn’t seem to get the clone method to work – well at least the event wasn’t firing in the Main.as. In the end I created a new custom event and dispatched that from within DatabaseConnection.as and that seemed to work:
Cheers
Ryan
To Ryan:
Make sure that the addEventListener in your Main.as is listening to the same event object type as your clone.
For example:
If I were to dispatch a TimerEvent.TIMER_COMPLETE in my DatabaseConnection.as completeHandler( ), the Main.as should have an addEventListener listening to TimerEvent.TIMER_COMPLETE (it must be the same, else it will fail)
I have tested this (e.clone) and it works for me 😀
if you want to try, below is a simple code:-
Main.as
MyTimer.as
@David: Is any of the code working so far?
@Ryan: Did ayu’s reply help?
@ayu: Thanks for helping Ryan!
Hi Ayu,
I referenced ‘Event.COMPLETE’ in both classes and it did not seem to fire the event. Perhaps the event needs to be cast to an explicit type? I’m not sure. There could also have been another reason why the event was not firing.
I will try to play around with it when I get some more free time. For now the custom event is working =) Thanks Ayu and Michael.
@Ryan
you can try placing a trace add the place where you are listening to the event (Main.as?)
If it traces xxx object, then you should listen to that xxx object.
Hi, excellent to have complicated things explained so simple!
Have a question about the scoop of a variable, when handling EventListeneres:
How can fTwo access variable a accessible to fOne?
may/ should/ can I use this instead? Is this valid? Is any better?
The general idea is really to pass a second parameter to the fTwo…
thanks!
/j
@javier
a function can’t access another function’s local variable.
this is because once the function has completed,
the local variable will be disposed (Not stored in memory)
one of the solution you can apply is to use
the class variable (public var / protected var / private var)
@ayumilove, thanks for your answer…
hmmm, I see now that my code was not as clear as i did see last night, with a lot of hours awake…
what I tried to say in the second example was if I can (or should, or shouldn’t) nest the function Two as a local function of function One – and so have access to f One’s local variable.
It is what I finally used, because in my simple example it was giving me the correct answers. But I really don’t know if in more complex situations the garbagecollector will destroy function One while function Two is still waiting for an event…
Do you know??
/br
/j
it should have looked like:
@javier
hmm that I do not know,
but its not a good idea to have nested functions,
it makes thing complicated,
just declare two class functions,
functionOne adds the eventListener to the class itself
functionTwo handles the event once he catches that particular event occuring
if the class instance is nulled (not used anymore) with no other
class using that particular class instance,
then the garbage collector will come and clear it away.
also, you must use removeEventListener, it is because it will keep on
waiting and listen to that event unless you use removeEventListener.
hello, how would i simplify this i have a lot of mouse over and outs to do in this project
here is an example of two of them how would i simplify this code? maybe a conditional statement? im a little lost thanks
Hey, sorry it’s taken me so long to reply. Let’s see…
@Ryan: Glad to hear you have it working in some way 🙂
@ayumilove: Thanks for helping Javier as well 😉
@Javier: I am pretty sure that the “anonymous” function you’ve created will not be garbage collected, unless you use a weakly referenced listener. However, I’m not sure whether it’d be able to get the value of
a
. My guess is that it wouldn’t… let me know what you find out!@rj2: How about this:
Michael,
I do get the value of
a
correctly from within functionTwo.I don’t want the functionTwo from “disappear” while waiting (in my tests it does not disappear, and works correctly), but on the other side I don’t want the listener from being kept more than necessary…
So using weak reference to the listener does not seem what I want, but does the removeEventListener do it’s work? Or can’t I reference it like this? :
thank you for all!
/j
Hey Javier,
Oh! Well that’s interesting, thanks 🙂
Hmm, that might work. Give it a go, see if you get an error 😉
i have checked, removeEventListener does not do its job.
why would you want to place it inside the function in the first place?
It’s bad coding.
Oh. Well, good to know.
HI Michael,
I’m new to AS3, I’m wondering if you could please help me out.
I have an index.swf that loads a projects_list.xml file. Each node is like this.
projects_list.xml file set up
The index.swf loads the thumbnails for all the projects. When the user clicks on a thumbnail image I need it to open a new xml file with the details for each project.
desc_con.xml file set up (details file)
Here is the edited down version of my AS 3 code with just the snippets I thought you would need to see. I just can’t figure out how to pass the “link” tag of the current project_list node to the var Full_xml= in the CallFull function.
Many thanks
Sylvia
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_project = myXML..project;
my_thumb_images = my_project.@thumb;
createContainer();
callThumbs();
}
function createContainer():void {
container_mc = new MovieClip();
container_mc.x = my_x;
container_mc.y = my_y;
addChild(container_mc);
container_mc.addEventListener(MouseEvent.CLICK, callFull);
}
function callThumbs():void {
for (var i:Number = 0; i < my_project_total; i++) {
var thumb_url= my_thumb_images[i];
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb_url));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.name = i;
var thumbText:String = my_thumb_name[i].toString();
htmlThumbText= thumbText;
thumbName.htmlText = htmlThumbText;
container_mc.addChild(thumbName);
I think I have found the solution.
I moved the event listener from the container_mc to the my_thumb
Then I used this code in the call_Full
Many thanks for your help!
@Sylvia: Must admit, I didn’t really follow that, but glad to hear you fixed it 🙂 Thanks for sharing your solution!
Hello Michael Williams!
Thanks for your article, but I have 1 question on the same theme.
Can you explain why we use dispatchEvent sometimes?
var now: Date;
var ct:Timer = new Timer(1000);
ct.addEventListener(TimerEvent.TIMER, onTick);
ct.start();
public function onTick(event: TimerEvent): void {
now = new Date();
var s:uint = now.getSeconds();
var m:uint = now.getMinutes();
var h:uint = now.getHours();
secondHand_mc.rotation = 180 + (s * 6);
minuteHand_mc.rotation = 180 + (m * 6);
hourHand_mc.rotation = 180 + (h * 30) + (m * .5);
}
Hi
I had written the above code to show the clock, but this code does not work.
when i run the simple script it works fine but when I am trying to create the events it does not work at all.
can you please help me for this? are there any settings to be done for running the events in AS3