AS1 OOP: Inheritance
         by senocular  

ASBroadcaster and Events for Class Instances
Previously, in using static properties of a class, we were able to keep track of the number of instances that were created for a specific class. That can be expanded on by not only counting instances, but controlling them. If, for each call of the class constructor, you were to place that instance within an array defined in that constructor, events, or calls to instances’ methods, could then be sent to each instance in that array just by cycling through and calling the appropriate method for each. There is, however, a better way. That way is through using ASBroadcaster.

ASBroadcaster is an inbuilt object in Flash that gives the capability of sending events to a list of listeners of that event to specific objects in your movie. Some objects, like Key and Stage, are already defined to behave this way. ASBroadcaster lets you create your own broadcaster objects which have their own listeners and can send them all the event of your choice. With OOP, you’d typically have a class broadcast events to all instances of that class.

A common mistake is assuming that such functionality can be achieved by calling a method directly from a prototype. That, of course is not the case. But why not? All instances have those prototype methods? If I call it from the prototype, won’t it call it for all of those instances? Nope. Remember, the prototype object is just a shared object. It’s a normal object in every other respect. Calling a method from that object would be no different than calling a method from some other single class instance. It will only run for that one object and no others. This is even the case if you try something like class.prototype = new MovieClip(). It’s just not going to happen. ASBroadcaster is the way to go.

If you don’t already know its use, you can find more about what ASBroadcaster is and how it works here. Otherwise its time to jump right in and start using it.

For a class making full use of ASBroadcaster capabilities, it would need to be a class where every instance needs to have a method called for it at any one time for some particular reason. One example might be giving raises to all employees of a company. Each employee has their own specific weekly income. A raise for every employee would mean an increase would have to be applied to each one of those incomes in every employees of the company.
 

// employee class definition
Employee = function(weeklyIncome){
this.weeklyIncome = weeklyIncome;
// make each created instance a listener of
// the class constructor
Employee.addListener(this);
};
Employee.prototype.getPayCheck = function(){
trace("Cha-ching! $"+ this.weeklyIncome);
};
Employee.prototype.getRaise = function(percent){
this.weeklyIncome += this.weeklyIncome*percent;
};
// initialize Employee to be able to send events to its listeners
ASBroadcaster.initialize(Employee);
Employee.giveRaise = function(percent){
// send all listeners the getRaise event and
// pass to it the desired percent argument
this.broadcastMessage("getRaise", percent);
};

 
humanReceptionist = new Employee(200);
monkeyTypist = new Employee(10);
humanReceptionist.getPayCheck(); // traces Cha-ching! $200
monkeyTypist.getPayCheck(); // traces Cha-ching! $10

 
// give all employees a 5% raise
Employee.giveRaise(.5);

 
humanReceptionist.getPayCheck(); // traces Cha-ching! $210
monkeyTypist.getPayCheck(); // traces Cha-ching! $10.5

Using a static method of the Employee constructor, all instances of that class can then be sent a similar event, in this case, getRaise. If you want to be more consistent with other Flash events, you could instead use a method name such as onGetRaise, though it’s not necessary. The “on”, does help you see that the method is an event method, so it might be something to consider in naming your events.

Now, if you didn’t already realize this, normal inbuilt Flash event’s aren’t coming to the class above. As it exists now, the only event any employee will ever receive is the getRaise event. The onEnterFrame event, for example, isn’t even close to being called for any employee. In fact, its reserved solely for movieclip instances. Any object you make, either generic or from one of your classes, will not be able to receive the onEnterFrame event on their own as movieclips do. With ASBroadcaster, though, you can get around that.

All you need is a movieclip host – some movieclip willing to spread the love of its onEnterFrame event down to the lowly objects of your choice. If none of your current objects are willing to volunteer, its ok. We can make a new one just for this purpose with createEmptyMovieClip. Just make sure you have a safe depth to keep it. The idea is to take the onEnterFrame received by the host clip and broadcast it to a list of listeners who need to receive it, those listeners being those “objects of choice”. These objects can be either individual object instances or, better yet, especially if all instances of a class are to receive an onEnterFrame event, class constructors. In using class constructors, you would have a static onEnterFrame method of the class constructor which would then be used to broadcast its onEnterFrame method to its own instances.

[ onEnterFrame from movieclip to class to class instances ]

This adds an extra step in the onEnterFrame execution, but it allows for individual classes to better regulate their own instances and the onEnterFrame events being called on them.

The following example has a single class which is defined as a listener of the onEnterFrame broadcasting movieclip created in depth 1000 of the current timeline. The event from the movieclip is sent to this class which then uses its onEnterFrame method to send it to all of its own listeners – or all the instances created by class.
 

// setup a movieclip to send onEnterFrame events to objects
this.createEmptyMovieClip("onEnterFrameEvent",1000);
ASBroadcaster.initialize(onEnterFrameEvent);
onEnterFrameEvent.onEnterFrame = function(){
this.broadcastMessage("onEnterFrame");
};

 
// define a child class
Child = function(name){
this.name = name;
this.ageInSeconds = 0;
// child will be setup as a broadcaster. Each instance
// can receive events when added as a listener
Child.addListener(this);
};
// method to be run every frame for instances
Child.prototype.grow = function(){
this.ageInSeconds += 1/20; // assuming movie at 20 fps
trace(this.name + "’s age: "+ this.ageInSeconds); // traces every frame
};
// make child a listener to the onEnterFrameEvent movieclip
// so that it will receive an onEnterFrame event
onEnterFrameEvent.addListener(Child);
// initialize child to be able to broadcast events
// so it can project its onEnterFrame to its instances
ASBroadcaster.initialize(Child);
// define an onEnterFrame
Child.onEnterFrame = function(){
// send the grow event to all child
// instances, and do so every frame
this.broadcastMessage("grow");
};

 
// make new instances of child and watch them grow
son = new Child("Sam");
daughter = new Child("Jessica");

 
/* Example output:
Sam's age: 0.05
Jessica's age: 0.05
Sam's age: 0.1
Jessica's age: 0.1
Sam's age: 0.15
Jessica's age: 0.15
Sam's age: 0.2
Jessica's age: 0.2
*/

Note that aside from the broadcasting movieclip, the onEnterFrame event doesn’t even have to be named onEnterFrame anymore. In fact, here, the child class sends the “grow” event to all instances as opposed to an “onEnterFrame” event, which it essentially is.

 

Prev Page
 



SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.