Prototyping The Blues Away

by Kevin Ready, All Rights Reserved

The prototype feature of ActionScript is one of the best kept secrets in a Flash programmer's arsenal. Becoming fluent in applying this technique does not take long, and it is not difficult to understand implications for its usage.

One reason that the prototype keyword has not been more widely used is that much of the documentation describing it, in both ActionScript and JavaScript, barely touch on how it can impact your coding. The prototype is often referred to as a singular item; perhaps as an ancestor or parent in an inheritance hierarchy. Other examples have shown it being used in a manner indistinguishable from other methods or properties. Rarely do any examples show you how to use it with built-in objects.

What is the Prototype Keyword for and what can I do with it?

The prototype keyword gives you a passport to fly in ActionScripting (and in its close relative, JavaScript). It puts you on an even footing with those that created the language itself. In simple terms, the prototype keyword enables you to add as many properties and methods as you choose to built-in and user-defined objects.

User-Defined Objects

To use this effectively with your own objects, one must think at which point will an object require more properties or methods. For instance, let's consider a PlayerObject() in a shooting game. var Player=new PlayerObject("Ashley"); function PlayerObject(name){ this.name=name; this.score=0; this.addScore=addScore; this.shoot=shoot; }

If you can define properties and methods yourself for an object, why would you need the prototype keyword to do so? Indeed, the need for prototyping your own objects is much less likely to occur than the need for extending built-in objects.

One of the most important reasons to prototype a user-defined object is that all instances of the object--whether already existing or not--can access its functionality. That means that you wouldn't need to create an additional PlayerObject to handle new code. You can extend the one(s) that have already been built by prototyping a method.

In the course of your game, let's assume that at a certain level, all players get the chance to zap opponents with laser beams. At this point, prototype could be used to provide the additional functionality (i.e., the lazerBeamBlast() method) to all players in the following manner:

PlayerObject.prototype.lazerBeamBlast=lazerBeamBlast;

Then, you would define a method

function lazerBeamBlast(){ // }

That would provide the code newly available for all instances of your user-defined object. To see a demonstration in JavaScript, look at the source of this page and see how the following works:

Test lazerBeamBlast - Extend PlayerObject

By clicking on Test text, you will see how Player.lazerBeamBlast is seen as "undefined." Once you extend the object by clicking on the Extend text, Player.lazerBeamBlast will then be seen as a function for Player, even though it was created before lazerBeamBlast was prototyped.

Extending Built-in Objects

Using prototype with user-defined objects is one thing; where the keyword is really useful is through extending built-in objects. Everything from Movie Clips to Array, String and Date Objects can be extended through the prototype keyword. Don't bother trying to look in the documentation for this--it's not there!

Here is an example that will reduce how much typing you do when you add an element to an array. In order to simplify the statement:

arrayName[arrayName.length]=elementThing;

The Array object could be extended and given a grow() method.

Array.prototype.grow=grow; function grow(element){ this[this.length]=element; }

Then, your new code would look like:

arrayName.grow(elementThing);

You might want to see if an indexed array contains a specific element:

Array.prototype.contains=contains; function contains(element,which){ outCome=false; for(var outC=0;outC<this.length;outC++;){ if(this[outC]=element){ if(which){ outCome=outC; }else{ outCome=true; } } } return outCome; }

This method gives you the opportunity to either test simply if an array contains an element, or to ask for the position of the element to be returned. A simple true/false test is performed by passing the element alone as a sole parameter; by passing a second parameter (I'd recommend the word "true"), the actual position of the element is returned.

Extending Built-in Flash Objects

MovieClips and more can be extended using the prototype keyword. Here's one that I use for setting colors:

MovieClip.prototype.setColor=setColor; function setColor(rgbValue){ // this is almost a carbon copy from the Flash manuals, // except that this one uses a method of the MovieClip, // rather than passing the MovieClip as an argument. setC=new Color(this); setC.setRGB(parseInt(rgbValue,16)); }

Now, whenever I want to add a rollover effect to a button inside of a movie clip, I can merely write:

on(rollOver){ this.setColor("DF9595"); } on(rollOut){ this.setColor("7f7f7f"); }

Similarly, you could create an animation method with start and stop coordinates, number of frames, and perhaps a passed method that is executed once the MovieClip arrives at its final destination.

Prototyping the Date Object and Building a Dynamic Calendar

Here are two prototyped extensions to the Date object that enable you to build dynamic calendars of any date. First, let's define the prototyped methods. Date.prototype.numberOfDaysInMonth=numberOfDaysInMonth; Date.prototype.firstDayOfMonth=firstDayOfMonth; function numberOfDaysInMonth(){ // To test for the number of days in the month, you add // one month to it, then subtract the original date from // the new date. Divide this by the number of milliseconds // in a day (86,400,000) to determine the number of days. if(this.getMonth()<11){ bDate=new Date(this.getYear(), this.getMonth()+1); }else{ bDate=new Date(this.getYear()+1, 0); } aDate=new Date(this.getYear(),this.getMonth()); return((bDate-aDate)/86400000); } function firstDayOfMonth(){ // First, to handle brower/operating systems that give erroneous dates, // a method tests for the year. if(this.getYear()<1000){ year=1900+this.getYear(); }else{ year=this.getYear(); } // once you know the year, you create a new date with the // same month as the existing date, with the first day // selected. then, you just grab the day. aDate=new Date(year,this.getMonth(),1); return aDate.getDay(); } � �

Once you know how many days are in the month and what the first day of the week is, you can build a calendar of your own design. Following is an implementation using both methods.

function setCalendar(year,month,day,emCee){ // The calendar is built by using the first day of the month and // year provided as arguments. The emCee is the name of the movie // clip that acts as the calendar. It contains six rows of seven // rectangular clips that include a text field "dateText" where // the number of the day is written. To ensure that the days of // the month are in alignment, it uses the firstDayOfMonth() and // numberOfDaysInMonth() methods to build the calendar. A test is // performed to see if the day is the passed day argument so that // a different color is used to view that day. if(year<1000){ year+=1900; } theMonth=new Date(year,month); for( theDay=theMonth.firstDayOfMonth(); theDay<(theMonth.firstDayOfMonth()+theMonth.numberOfDaysInMonth()); theDay++){ theMC=eval(emCee+".day"+Math.floor(theDay/7)+theDay%7) theMC.dateText = ((theDay-theMonth.firstDayOfMonth())+1)); if(((theDay-theMonth.firstDayOfMonth())+1)==day){ theMC.goBG.setColor("ff7f7f"); }else{ theMC.goBG.setColor("ffff7f"); } } } �

The limits to what you can do with the prototype property are left to your imagination. You can attach as many method or property prototype extensions as you choose. I'd recommend defining your prototype definitions as close to the first frame of the movie as possible. Once an object has been extended, its extensions can be used throughout a movie. To remove a property or method, you can merely define it as null or "undefined" as your code needs require. This cannot be done to built-in objects.

PlayerObject.prototype.lazerBeamBlast="undefined"; �

In ActionScript and JavaScript, knowing that you have the prototype keyword as a tool will give you that much more incentive to become familiar with object-oriented techniques. The deeper you delve, the more you will unleash the power of scripting.

 


  © 2002 by Kevin Ready, All Rights Reserved