Getting Flashy
So I have finally made the jump into Flash games. I used flash a long time ago and its really matured since, so I thought I would drop a few notes as I go about things that just aren't really obvious.
The most useful but toughest thing I have got into is the idea that spirtes and classes are now seperate but tightly bound to each other. While this is standard best practice, action scripts didn't use to be stored in seperate editable text files -- all the resources in a Flash document used to be contained inside the *.fla file.
This is a good thing but it does create some interesting conditions and design patterns.
Have Some Class
ActionScript has always been a "loosely class oriented" language, like PHP -- classes exist but most things can be done with sprite-bound scripting and the time line.
If you are designing games, however, the class system really comes into its own, and AS3 has really made OOP pretty mandatory.
All classes MUST be stored in action script files that are bound in packages. This "Packaging system" is fairly standard coding practice: class foo.bar.Bax is stored in file "foo/bar/Bax.as" -- the path being relative to the calling Flash(.fla) file.
You can of course have a "flat" package, say "game", and put ALL your classes in the same packaage to simplify your mind, but class packages really do make large project organization a lot easier. (and a game is a large project in almost all cases.)
here is the pattern for the above file:
package foo.bar {
class Bax {
function Bax() {
// the constructor: has the same name as the clsss.
} // end constructor
} // end class
} // end package
In order to "expose" or use one class inside another you use the import construct:
package foo {
import foo.bar.Bax // or foo.bar.* to include the entire bar package
class Fey {
public function Fey() {
b2 = new Bax(); // this will happen AFTER b is intialized.
}
/* ************** properties ************ */
private var b:Bax = new Bax(); // creates a new Bax every time this class is instnatiated.
public var b2: Bax; // also creates a new Bax -- explicitly -- in the Fey constructor.
}
Sprite/Movie Class Binding
Flash is of course a unique beast -- an animation program that has retroactively been tooled into a game design/client side application and OOP system. Because of this, sprites -- movies and buttons -- predate the formal OOP structure. And they have a lot of features of a class, but a movie/button is NOT a true class.
The ways in which it IS a class is that:
- a movie or sprite has a "Platonic" definition -- a collection of timelines, graphics and sub-movies -- that can be "Instantiated" in one of two ways: class binding (see below) or simply dragging it onto the "stage".
- movies have properties -- editable with the property dialog.
Movies are by default bound to a native class - flash.display.MovieClip or flash.display.SimpleButton. (other sprite base classes are probably available.) The base class for a given movie can be defined in the properties dialog box.
The concept of binding is VERY important to understanding how classes work in Flash. The class bound to a specific sprite defines the properties and methods that can be used on a particular instance.
However classes, as shown above, are in the Flash context, defined in remote text files and can be instantiated with the
var m:classType = new classType();
script convention, and can have a wide and user-defined range of properties and methods.
If you define a class that you want to bind to a given sprite,

you can define a class file (in this case, "game/synerg/tiles/Farm_tile") that binds itself to the sprite -- and vice versa. the following script, if present in the base movie...
import game.synerg.tiles.Farm_tile; var ft:Farm_tile = new Farm_tile(); ft.x = 100; ft.y = 100; addChild(ft);
...will add a Farm_tile sprite to the stage, at the given location. Sure, you could just drag it from the library panel, but this shows two things:
if you create an instance of a CLASS that is bound to a SPRITE, the graphics of the sprite happen when you create a new CLASS in action script. Its important to note you don't HAVE to bind classes to sprites. You can create a utility class and not bind it to any sprite. Also, this works in reverse -- if you drag a farm tile onto the stage, it will also have all the properties and methods of the Farm_tile CLASS.
Here is another "Trick" -- if you refer to a class that doesn't exist in the codebase, Flash "Magically" defines a class of the given name that extends the base class given below:

import game.synerg.tiles.Farm_tile; var ft:I_have_no_class = new I_have_no_class(); ft.x = 100; ft.y = 100; addChild(ft);
... will work EVEN IF THERE IS NO SCRIPT FILE defining the class - i.e., no file I_have_no_class.as ANYWHERE! Flash, at runtime, creates a class definition that extends the base file and name-maps it to the sprite in order to enable class-binding behavior.
You don't have to DIRECTLY extend a display class - you can create a base class that extends flash.display.MovieClip (or whatever) and extend THAT class with a seond class defintion and bind it to a sprite:
package game {
import flash.display.*;
class I_have_no_sprite extends flash.display.MovieClip
{
// put whatever functionality you want to share here
} // end class
} // end package
package game {
class Sprite_class extends I_have_no_sprite {
} // end class
} // end package
...and use the game.Sprite_class as a bound class within a sprite's property dialog.
Ogres have layers; Movies have layers; sprites don't.
One thing I got confused with briefly was that the concept of layers exists ONLY in the flash GUI -- you can't access a layer by name (or in any other way) inside action script.
Sprites in a running movie exist in a stack -- it doesn't matter what layer they were defined as, sprites exist in an ordered stack to preserve the "layery" effect of having some sprites in front of another. Its as if the layers were folders and the sprites were sheets in the folders -- when the movie runs it dumps the pages out of the layers in the order that they occur, preserving relative order but LOSING the layer/sprite association.
If you want to have "layery behavior" you have to create sprites that function as layers. for instance, in the Synerg game, I have a layer for grass, a layer for farms, and a layer for cows. But since grass, farms and cows are added by script, I can't automatically ensure that the cows are always added ON TOP of the farms and the grass (and the farms are on top of the grass).
In order to get "layer like" behavior you have to create sprites in the proper order and attach (with actionscript) sprites to these "layer stubs" as children. Because a sprite can never appear above the child of a sprite that is above its parent, layer stubs give you the functionality of layers, even though they themsleves are simply (most likely invisible) sprites.

The classics: Interfaces, extension/inheritance, and Abstract Classes
I have some good news and some bad news. The good news is that ActionScript does indeed have Interfaces and they behave pretty much as you'd expect -- defined with the interface keyword, no bodies in the methods, and hooked in with the Implements.
This is good to know as when you uses type-sniffing Flash is pretty diligent about determining type violation.
I suppose you guessed what the bad news is ... there is no Abstract Class system in Actionscript syntax. That is not to say that you can't create "Abstracty Classes" that you don't intend to instantiate. You just can't use the "abstract" keyword in any class/method definitions.
inheritance uses the classic model -- class a extends class b, no multiple inheritance. The only hook worth noting is you have to decorate any method overrides with the prefix "override":
class Abstracty_Math
{
public function add(a, b){ return a + b; }
}
class Sucky_Math extends Abstracty_Math {
override public function add(a, b) { return a + b + Math.random(); }
}
Debugging: Tracing, try/catch/error, and toString
The basic "echo to output" function is trace(message:String). This comes in handy. Also, the familiar toString() magic extension is present in actionScript, meaning if you define a class as such:
class Foo {
private var id: String;
function Foo(pID){
id = pID;
}
override public function toString(): String {
return id;
}
}
then you can echo an object as such:
var f:Foo = new Foo(1356);
trace ("I made a " + f);
// output reads "I made a 1356"
Also you have the standard try/catch loop available. The one twist is that instead of using an "Exception" class, the standard throwable error is of type Error. So you can write a cheker as such. (note -- this is not my idea of a "Good way to write code" -- it just illustrates throwable errors well.)
function add_positive_numbers(a:int, b:int){
try {
if (a < 0) throw new Error("APN error: first value, " + a + ", less than zero.");
if (b < 0) throw new Error("APN error: second value, " + b + ", less than zero.");
return a + b;
} catch (e: Error) {
return null;
}
}
Note -- the error strings will never be displayed because they are "caught".


Randomizing Arrays
http://mrsteel.wordpress.com/2007/05/26/random-array-in-as2-as3-example-... contains a useful script for randomizing arrays
Post new comment