A little help with event listeners...
Having an eye on your event listeners is really essential in flash. Not only that forgetting to remove a listener will keep an object away from garbage collection forever – there is another evil habit often done: simply layering different MovieClips above each other to “hide” the previous menues and stuff. That sure makes all the underlying stuff invisible to see – but all the buttons that are down there are still accessible via the TAB-key.
The basics
To add an event listener to an object (let’s be correct: to an EventDispatcher) you call my_object_name.addEventListener(...) with a bunch of parameter. To remove it you call my_object_name.removeEventListener(...). I assume you already know how to use them and maybe also discovered some problems while keeping track of all the listeners.
Introducing the ListenerAdder
ListenerAdder is a class you can instanciate and tell all the event listeners you need. It’s able to add them all at once or remove them. That’s all. Sample code:
... my_listener_adder = new ListenerAdder(); // my_listener_adder is declared as a private var of the current class my_listener_adder.injectListener(my_button1, MouseEvent.CLICK, doOnBtn1Click); my_listener_adder.injectListener(my_button2, MouseEvent.CLICK, doOnBtn2Click); my_listener_adder.injectListener(my_button3, MouseEvent.CLICK, doOnBtn3Click); my_listener_adder.injectListener(my_button4, MouseEvent.CLICK, doOnBtn4Click); my_listener_adder.addAllListener(); // all listeners that have been "injected" before are now added ...
The parameters for injectListener just work like the normal addListener(...) on an EventDispatcher – there’s only one additional parameter at the very beginning: the EventDispatcher itself.
So the ListenerAdder knows about all your listeners. You can add them all by calling addAllListener() or remove them with removeAllListener(). Now you have only one place to define all your listeners – but add and remove them where you need. You can use your class constructor to define the ListenerAdder and call the add and remove functions when you want to activate or deactivate all listener.
That’s e.g. what I do when I switch between menu screens: While the menu is fading in there are no listeners active. After the fade in animation I addAllListener. Immediately before the fade out animation is played I removeAllListener again.
It’s really helpful, I swear
Till now the ListenerAdder class is quite ok, but it doesn’t knock your socks off. But there is one way of use that makes it really helpful:
Imagine you’re doing a game that has lots of going on, like a game world with hero-, enemy- and background-movement ON_ENTER_FRAME and something else running ON_TIMER, and the hero reacting ON_KEY_DOWN and a pause menu that appears ON_CLICK.
Now your hero drops dead because the player hits an enemy and while the death animation is playing and the respawning is done you want the enemies and your world to “live on” but you don’t want the player to do key interactions any longer or let him open the pause menu. You could of course place if (!player_is_currently_dying) {} all the way through your sourcecode, but you could also do the following instead:
Use different ListenerAdder for different kinds of interaction. Like…
var world_la:ListenerAdder; // general stuff like world animation, ... var interaction_la:ListenerAdder; // key and menu interaction
You can put all the event listener regarding user interaction to interaction_la if you want to block them simply call interaction_la.removeAllListener(). Let’s revisit the above example: as soon as the player character dies, we remove all interaction listener. After all the dying and respawning animation/screen-fading is done we addAllListener again.
That’s just a simple example. Using different LisenerAdder for different kinds of interaction already saved me a lot of trouble, you should give it a try ;)
Download and use
You can download the file above or paste the source code at the end of this post to an empty file and save it as “ListenerAdder.as”.
It’s ActionScript 3 but should also work with a2 I guess, maybe with minor modification. I could have used the slightly faster vector instead of an array but this way it’s also compatible with flash9 (vectors came with flash10).
To use it simply extract the zip and copy it to your source folder and import de.headjump.ListenerAdder everywhere you need it. Make sure to keep the folder structure like it is (de/headjump) – otherwise the package path won’t work properly. Of course you could just change the package within the actionscript file to whatever you like – but I’ll post some more classes and stuff later on that’ll be crosslinked at some points, so you should really leave the package structure as it is.
If you consider any problems with the file or have an idea on how to improve it please drop me a message.
That’s the entire source:
package de.headjump {
import flash.events.EventDispatcher;
/**
* ...
* @author Dennis Treder (info@dennistreder.de) http://www.headjump.de
*/
public class ListenerAdder {
private var m_events:Array;
private var m_active:Boolean
public function ListenerAdder() {
m_events = new Array();
m_active = false;
}
public function injectListener(target:EventDispatcher, type:String, func:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
var lo:ListenerObject = new ListenerObject(target, type, func, useCapture, priority, useWeakReference);
m_events.push(lo);
if (m_active) {
lo.activate();
}
}
public function addAllListener():void {
m_active = true;
for (var i:int = 0; i < m_events.length; i++) {
ListenerObject(m_events[i]).activate();
}
}
public function removeAllListener():void {
m_active = false;
for (var i:int = 0; i < m_events.length; i++) {
ListenerObject(m_events[i]).deactivate();
}
}
}
}
import flash.events.EventDispatcher;
class ListenerObject {
private var target:EventDispatcher;
private var type:String;
private var func:Function;
private var useCapture:Boolean;
private var priority:int;
private var useWeakReference:Boolean;
public function ListenerObject(_target:EventDispatcher, _type:String, _func:Function, _useCapture:Boolean = false, _priority:int = 0, _useWeakReference:Boolean = false) {
target = _target;
type = _type;
func = _func;
useCapture = _useCapture;
priority = _priority;
useWeakReference = _useWeakReference;
}
public function activate():void {
if(target != null) target.addEventListener(type, func, useCapture, priority, useWeakReference);
}
public function deactivate():void {
if(target != null) target.removeEventListener(type, func, useCapture);
}
}


