Written by: Ka Wai Cheung, http://www.project99.tv
Difficulty Level: intermediate
Requirements: Flash MX 2004
Download FLA

Communicating between Flash objects in a more object-oriented way by Ka Wai Cheung, May 2004

With the release of Flash MX in 2002, Flash added a new twist to their event handling model. Suppose you are building a simple interactive movie in Flash that involved a teacher and 20 of her students. Let's say you wanted to have a few buttons at the bottom of the movie that would dictate what the teacher said to the students, and then have the students react to her statement.

Before MX, the out-of-the-box method would have been to have two disparate events execute when you clicked on one of the buttons. Suppose you built a button that reads "Class is about to begin." When you click on this button, you would build one event for the teacher (her saying, "Class is about to begin!"), and one response for the students (however they may respond to this). The triggering of the events would be tied to the button. The fact that the students reacted to the teacher was, in an OOP sense, completely arbitrary. It just so happens that you specified these two events to execute when the button was clicked.

With MX and MX 2004, we can now think of the student-teacher paradigm in a more real-world sense. The out-of-the-box method now would be to initialize the teacher as a "broadcaster" and each student as a "listener." Thus, when the teacher cries "Class is about to begin!" the event that triggers the students' reaction stems directly from the teacher object and not from the button you just clicked.

The implementation of the broadcaster-listener model is very simple. In a nutshell, you can designate any event-driven object X as a broadcaster (named the AsBroadcaster class) using:

AsBroadcaster.initialize(X);

You can then add any number of instances of objects (Y and Z) as listeners to the object:

X.addListener(Y);
X.addListener(Z);

You can then signal a message to these instances via the broadcastMessage() method:

X.broadcastMessage("ClassBegin");

Flash will then look for Y.ClassBegin() and Z.ClassBegin() methods to invoke.

(For a quick and excellent primer on the Broadcaster object and listeners, please read Santiago Esperanza's article "Listeners and ASBroadcaster" here .)

While the broadcaster-listener model works well, I found it odd that you actually had to instantiate the listeners on a per-instance basis. So, in the teacher-student model, suppose we put 20 instances of a student movie clip on the root timeline. I'd have to invoke 20 addListener() methods to tie each student to the teacher.

If I were dynamically duplicating one student 20 times, it would be less coding work, since I could run the addListener method within the loop that duplicates the student. Something like:

for (var i==0; i < 20; i++)
{
        // Create the duplicate student...
        _root.mc_student.duplicatemovieclip("mc_student" + i, i, initObject);
        // Make the student a listener of the teacher...
        _root.mc_teacher.addListener("mc_student" + i);
}

An even better object-oriented approach that can be achieved with MX 2004 would be to link a student movieclip to an ActionScript class file called student, which would inherit the MovieClip class. Here's a look at the oh-so-simple student.as file code:

class student extends MovieClip {
        function student()
        {
                // I'm a new student!
        }
       
        function ClassBegin()
        {
                // Do something to react to class beginning!
        }
}

Now, I can link the student movieclip to the student class, so every instance of the student will have a class associated to it. (In MX 2004, you can link objects to custom classes by right-clicking on the object within the objects library, clicking "Linkage...", checking the "Export for ActionScript" box, and assigning the class name to the object). So, regardless of whether I duplicate mc_student, or create new movieclips that are linked to the student class, I can add them all as listeners to the teacher with the following snippet (assuming they are on the root timeline):

// Make every student in the movie a listener of the teacher...
for( var i in _root) {
       
        if(_root[i] instanceof student) {
                mc_teacher.addListener(_root[i]);
        }
}

Thus, when the teacher broadcasts the message that class is about to begin, all instances of the student class can react in their own way.

mc_teacher.broadcastMessage("ClassBegin");


In the example above, each of the colored students is a different movieclip linked to the student class (in student.as). I've duplicated the green student using duplicatemovieclip(). Clicking on either button broadcasts a message from the teacher, which then invokes the corresponding listener functions within the student class. In this case, each of the student movieclips simply outputs a response string within the student class.

The addListener method uses the same code as above. It loops through all instances of a student and adds them to the teachers _listener array.

What's nice about this is that I don't have to think about adding random objects to mc_teacher's listener array (If you read Esperanza's article, you'll find out that addListener() really just adds the instance names of the listener in question to an array). I know, by design, that any object that is linked to the student class will be a listener of the teacher. This becomes a far more secure implementation of the teacher-student model, and also makes the object-oriented model even more tightly integrated.

You could (and should) even be extra suave by imbedding the for loop above into a custom function, and just pass in the class name and the broadcaster instance into it.

All in all, the broadcaster-listener model is a nice paradigm to work with in MX. However, in the real world, the adding of listeners doesn't make all that much sense. In a classroom, when the teacher says (or does) anything, everyone should have the capability to listen and react. In a better model, there either wouldn't be a need to invoke the addListener() method or there would be a standard way of linking entire classes as listeners.

In a future article, I'd like to present an extension around the current AsBroadcaster object that would at least give the flexibility to allow a broadcaster to self-add classes of objects to its _listener array, instead of having this invoked through an external function.