by
senocular
AsBroadcaster
We'll get into more usage with Listeners, but not before
dipping a little into the AsBroadcaster object and
seeing what it really accomplishes. This object is
closely tied to listeners, more than you may think. Each
one of those event broadcasting objects listed before
(Key, Mouse, Selection, Stage, TextField) was
initialized behind the scenes by Flash using
AsBroadcaster. This is what enabled them to broadcast
that event for listeners to handle.
The AsBroadcaster object itself, despite its presumed
intimidation, is simply a generic object with one
method, initialize. This is used on other objects to
transform those objects into broadcasting capable
objects. In doing so, it adds three new methods and a
new property to the transformed object. These methods
are addListener, removeListener, broadcastMessage and
the property,
_listeners.
addListener
lets you add a listener to your new broadcasting object.
removeListener
lets you remove one.
broadcastMessage is the command that the
initialized object runs to generate an event to be sent
out to the listeners (like onMouseDown) while _listeners
is a list of all the listeners associated with the
broadcast object. So, for the usage of AsBroadcaster, we
get:
- AsBroadcaster.initialize(objToBroadcast);
- objToBroadcast.addListener(listenObj);
- objToBroadcast.removeListener(listenObj);
- objToBroadcast.broadcastMessage("event");
- objToBroadcast._listeners;
Note that you do not create
instances of the AsBroadcaster object as you would with
other objects using the new keyword. It is simply a
container object for the initialize function, which
could just have easily been a stand alone function.. The
only time AsBroadcaster is actually written in code is
when an object is initialized to become an object
capable of generating an event.
The Mouse object, for example, is automatically
initialized with the AsBroadcaster object in Flash. It
adds the addListener and removeListener methods to the
Mouse object allowing you to add your own listeners and
also runs broadcastMessage whenever you press, move,
and/or release your mouse button. So if you click your
mouse, Flash runs an internal
- Mouse.broadcastMessage("onMouseDown");
and any listeners of the mouse object, like any
movieclip for example (which is automatically made a
listener of the Mouse object), will recognize the
onMouseDown event and run any code they have associated
with it.
Example 2
Now that we have a basic understanding of what
AsBroadcaster does, ew can now use it to generate custom
events from custom broadcaster objects for custom
listeners to respond to. This example will still use the
literal way of thinking as in Example 1, that being
thinking of your listener objects as objects which are
aware and listen for events to occur.
For this example I'm going to have to ask you step
back in time a couple thousand years to the time of old
where kings ruled and court jesters fooled. What we'll
do here is make some new objects; a king and a royal
subject, and use AsBroadcaster to control how they
interact. The king, being a king, is going to give
orders and our royal subject will listen for
these orders and carry out a certain action when
received. So in this example we have to first create our
objects and assign them their traits/abilities. The
king, for example, when we define him in actionscript as
an object, will just be like every other object so we'll
have to also make him a leader (using
ASBroadcast.initialize) while our subject will
have to be hired (using
addListener)
as a servant of the king and be given a job to do based
on the commands given. Here's the code:
- // a King is born!
- King = {};
- // our King is declared a leader
- AsBroadcaster.initialize(King);
- // a royal subject is born!
- subject = {};
- // our subject is now hired to listen
to the king
- King.addListener(subject);
- // now we tell our subject his job
- subject.onKingScream = function(){
- trace("brings grapes");
- }
- // here we just make the King scream
twice
- // just for the heck of it ;)
- King.broadcastMessage("onKingScream");
- King.broadcastMessage("onKingScream");
When the King broadcasts his screams, the royal
subject, as a listener, hears the screams and runs the
onKingScream function its been assigned. This is the
same thing which happens if you defined an onMouseDown
event for a movieclip. When the mouse broadcasts the
onMouseDown event, the movieclip runs its onMouseDown
function. Here we are just using our King to broadcast
the event and the subject object to listen and respond
to that event. Any object you make can be used as a
broadcaster broadcasting any event you want it to. You
can even make predefined objects broadcast new custom
methods as well, which brings us to Example 3.
Example 3
This quick example adds broadcaster functionality to a
predefined actionscript object. This uses the Math
object and a movieclip called ball_mc. Lets take a look:
- // initialize Math object to be a
broadcaster
- AsBroadcaster.initialize(Math);
- // create a new function for the Math
object which
- // returns the sum of two numbers.
Included is the
- // broadcasted onSum event
- Math.sum = function(a,b){
- this.broadcastMessage("onSum");
- return a+b;
- }
- // make the ball_mc movieclip a
listener of the Math object
- Math.addListener(ball_mc);
- // sets the ball_mc to to goto and
play frame 2 whenever
- // the onSum event occurs (called when
ever Math.sum is run)
- ball_mc.onSum = function(){
- this.gotoAndPlay(2);
- }
Now, whenever Math.sum is used on anything, anywhere
in Flash, the ball_mc goes to and plays its frame 2.
How AsBroadcaster Really Works
How exactly does this generic object AsBroadcaster add
this wonderful functionality to another object anyway?
Its no secret. Its not even that hard to understand or
even do without the AsBroadcaster object itself. All
AsBroadcaster.intialize does to an object is add to it
an array called
_listeners
and gives it some new methods to control the objects
placed in this array.
addListener
adds an object in the array,
removeListener
removes one, and
broadcastMessage runs, for each object in the
_listeners array, a function with the same name as the
passed string. In fact, though AsBroadcaster is a Flash
MX object, its functionality can be implemented in Flash
5 all the same. The following code can be added to a
Flash 5 movie to add custom AsBroadcaster functionality:
- AsBroadcaster = new Object();
- AsBroadcaster.addListener = function(listener){
- this.removeListener(listener);
- this._listeners.push(listener);
- return true;
- }
- AsBroadcaster.removeListener = function(listener){
- var i = this._listeners.length;
- while(--i >= 0){
- if(this._listeners[i] == listener){
- this._listeners.splice(i,1);
- return true;
- }
- }
- return false;
- }
- AsBroadcaster.broadcastMessage = function(theEvent){
- var i = this._listeners.length;
- while(--i >= 0){
- this._listeners[i][theEvent]();
- }
- }
- AsBroadcaster.initialize = function(obj){
- obj.addListener = this.addListener;
- obj.removeListener = this.removeListener;
- obj.broadcastMessage = this.broadcastMessage;
- obj._listeners = [];
- }
This creates the AsBroadcaster object and gives it
the
addListener,
removeListener
and
broadcastMessage functions, which when initialize
is called, gets passed down and copied to the
initialized object. The object passed also gets the
_listeners array which is used to hold all the
listeners. The internal code use in Flash MX to define
the AsBroadcaster object is very similar.
I said it adds "custom" AsBroadcaster functionality
because using this in Flash 5 doesnt give you the full
functionality of Flash MX. Yes you can create your own
broadcaster objects and your own broadcast events, but
it does not mean that your Mouse object will
automatically start broadcasting the onMouseDown event
when the mouse is pressed because, as it exists in Flash
5, the Mouse object doesnt know when that happens.
Because of this, our Example 1 will not work in Flash 5,
though Example 2 and 3 will.
Another difference with this example is that, here,
for this Flash 5 version, you can't pass arguments into
broadcastMessage to be received by your listeners. In MX
you are able to pass any number of arguments after the
event parameter in a broadcastMessage call to have those
arguments passed to the listeners' call of that event.
An example of this is in the Appendix below. Flash 5
just doesn't have the capability to make this possible
because it cant parse the arguments followed by the
event passed into the broadcastMessage call. In MX this
would be achieved with the Function.apply method.
Broadcaster as List Holder
With this new attained knowledge of how
AsBroadcaster really works, you can see that listener
objects are, themselves, not altered in any way when
they become a listener. This kind of contradicts the
whole perception of these objects having gained this new
ability of listening. In fact, all that happens is the
broadcaster object is given a reference to that listener
object and then is able to run any method of that
listener it desires whenever it wants to (assuming the
method exists). Alone, the listener object has no way of
losing its listening ability unless the broadcaster
itself is told to delete the listener out of the
_listeners
array using
removeListener.
With that in mind, try instead not to think of
listeners as listeners but just plain ordinary objects
out off in the world somewhere. They mind their own
business and you dont have to worry about them, what
they can do or what they know, just that they exist. Now
consider the broadcast object. This guy really is the
head object in charge. He controls the commands and
holds the list that says which one of those ordinary
objects out there he can give these commands to. Any
object on that list he can give commands to, an those
objects, as long as they can recognize the command
given, will have to do whatever the broadcaster object
says; just because that's just the way it is. And that is
how it is in Flash.
Example 4
This example I think embodies that train of thinking
with the broadcaster being in charge. Here, the
broadcaster will be the all mighty Santa Clause,
because, after all, he has the power to control the
happiness of all the children (and even many of the
adults) of this world. Santa, as we all know, has his
naughty and nice lists and depending on who is naughty
and who is nice, Santa shall decide the fate of their
happiness. What we'll do here is add people to the nice
list and give anyone on it a present!
The example itself is structured much like Example 2,
though there are some added elements and the
AsBroadcaster object is renamed to cohere more to the
Santa Clause metaphor. Here it is (note: some OOP used
but the code sample is more to get an idea of how
AsBroadcaster operates and a totally complete
understanding isn't necessary)
- // metaphor definitions - just to make
things sound right
- // person class to make Person objects
- Person = function(name){
- this.name=name;
- }
- // important person class to make
ImportantPerson objects
- ImportantPerson = function(name){
- super(name);
- }
- // important person is a subclass of
person
- ImportantPerson.prototype = new Person();
- // rename addListener
- ImportantPerson.prototype.addToNiceList =
function(n){
- this.addListener(n);
- }
- // rename broadcastMessage
- ImportantPerson.prototype.ForAllOnList =
function(n){
- this.broadcastMessage(n);
- }
- // traces the _listeners array
- ImportantPerson.prototype.ReadNiceList =
function(){
- for(all in this._listeners){
- trace(this._listeners[all].name);
- }
- }
- // rename AsBroadcaster object
- NiceList = AsBroadcaster;
- // rename initialize object
- AsBroadcaster.giveTo = AsBroadcaster.initialize;
- // end definitions
- // make Santa do his thing
- SantaClause = new ImportantPerson("Santa Clause");
- NiceList.giveTo(SantaClause);
- Tommy = new Person("Tommy");
- Tommy.givePresent = function(){
- trace(this.name + " jumps for joy!");
- };
- Sarah = new Person("Sarah");
- Sarah.givePresent = function(){
- trace(this.name + " says, 'Thanky Santy!'");
- };
- Trevor = new Person("Trevor");
- Trevor.givePresent = function(){
- trace(this.name + " thinks, 'But Ive been
naughty!?!'");
- };
- SantaClause.addToNiceList(Tommy);
- SantaClause.addToNiceList(Sarah);
- trace("Who's on the Nice
List?\n-------------------");
- SantaClause.ReadNiceList();
- trace("\nGive Nice People
Presents!\n-------------------");
- SantaClause.ForAllOnList("givePresent");
When run, this code traces both Tommy's and Sarah's
givePresent functions, but poor little Trevor, because
he was naughty and not added to the nice list, recieved
no present.
Advantages
It's important to note why you would want to use
AsBroadcaster. At first it may seem overly complicated,
but it does add an 'easier' method of interfacing with
multiple class instances. More importantly, however, is
that, despite the fact that AsBroadcaster really isn't
anything completely new (as you saw a Flash 5
implementation was created and as I have mentioned, you
have probably done something similar in the past),
broadcastMessage is a great deal faster in looping
through listeners than a normal actionscripted loop is.
In fact, using AsBroadcaster can cut loop time by about
half! This is because broadcastMessage uses an internal
loop mechanism, ASnative(101, 12), to loop through the
listeners array which is much faster than the loops
produced by Actionscript.
Conclusion
As you can see, the AsBroadcaster object and the use of
listeners adds a whole new perspective in how you can
program your Flash applications. Though maybe not a
new function of Flash it may change the way you'll
want to handle and recognize events as they occur within
Actionscript. Now you can have multiple objects in a
scene all react to a broadcasted "onEarthquake" event
with little effort and much speed.
Senocular
Some AsBroadcaster related scripts:
- /* give all movieclips ability to
broadcast */
- AsBroadcaster.initialize(MovieClip.prototype);
- /* broadcast event only to movieclips
in a listeners list */
- initiatedBroadcastObject.broadcastToMovies =
function(theEvent){
- var i = this._listeners.length
- while(--i >= 0){
- if(typeof(this._listeners[i]) == "movieclip"){
- this._listeners[i][theEvent]();
- }
- }
- }
- /* send variables through a
broadcasted event */
- listenerObj.onEvent = function(argument){
- trace("listenerObj recieved " + argument);
- }
- initiatedBroadcastObject.broadCastMessage("onEvent",
"passed variable");
- // traces "listenerObj recieved passed
variable"
- /* make an object listen to multiple
broadcasters at once */
- Object.prototype.listenTo = function(objs){
- var i = 0, l = arguments.length;
- for (i=0; i<l; i++){
- if (!arguments[i].addListener)
AsBroadcaster.initialize(arguments[i]);
- arguments[i].addListener(this);
- }
- }
- /* determines if an object is a
broadcaster with listeners */
- Object.prototype.isBroadcaster = function(){
- return (this._listeners.length) ? true : false;
- }