Saturday, November 8, 2008

Managing and controlling unnamed movieclip instances on the stage at runtime

Here is a problem. Let's say you have a situation where you have a bunch of movie clips on the stage. None of them [or some of them] are given an instance name and you have to somehow control all of them through ActionScript at run time. How do you do it?
Good question. Let's take look at a real world example.
You have to create a game in flash that will enable the user to drive a little car on the road and avoid a bunch of obstacles. The car movie clip has to "drive" on top of a map movie clip. That map is just a big square divided into smaller squares called tiles. So let's say your map is a 420 x 420 pix and it's divided into 64 tiles 60 x 60 pix each. Some tiles are road tiles, others have trees, buildings, or other crap drawn on them. We're interested only in road tiles, because, our car has to navigate on road tiles only. So, the graphic designer team created this kind of map for you and let's say it has 30 road tiles and a car movie clip. In addition, the designers created another 20 similar maps in varying sizes and road configurations. Some maps are big 840 x 840 pix with hundreds of road tiles. You get the idea. The problem is, those road tiles are not given instance names! There is no way you're going to make any one name thousands of tiles with names like: mcRoadTile_Straight, mcRoadTile_Turn_East_North, etc... It's horribly tedious and inefficient use of designer's time! You as a programmer have to find a way to program the car to "sense" what kind of tile it's on (straight or turn, or 4way stop or intersection etc...) and figure out if it can drive forward or turn. How do you know what kind of tile you're on? You can't use a car.hitTestObject(???) because your tiles are not named on the stage. You have no clue where you are. Keep in mind that the game should load different maps from the server in SWF format to enable the user to drive in on a different map every time you start the game. So, what do you do?
You have to somehow describe the properties of each tile (i.e. isTurnNorthPossible:Boolean = false, isTurnWestPossible=true etc...) and put the tiles in an array so that you can have control over them at run-time. That means that each tile should be linked to a class that is going to describe that particular tile and in the constructor of each tile you have to put some code to force it to "register" itself into an array inside some tile manager class. Like this:

package maps.classes.tiles {

public class Tile_Straight_East_West extends MovieClip implements ITile {

public function Tile_Straight_East_West() {

//dispatchEvent(new CustomEvent("REGISTER_ME", this)); //doesn't work

//Map is the DocumentClass
Map(this.parent).tiles_array.push(this); //works
}

public function isPassableFromDirection(direction:String):Boolean {

if(direction == EAST) {
return true;
}
else if(direction == NORTH) {
return false;
}
else if(.......) {
}........
}

}

}

//This is the Map (DocumentClass)
package {

/**
This is a document class
*/
public class Map extends MovieClip {

public var tiles_array:Array = new Array(); //public array is visible to all movie clips

public function getCurrentTile():ITile {
for(var i:int = 0; i < tiles_array.length; i++) {
if(car.hitTestObject( tiles_array[i]) == true) {
return tiles_array[i];
}
}
return null;
}

}
}

This technique of registering all movie clips of a particular type in one location is very useful.
Now you can tell the designers to do what they do best and not worry about naming movie clips at all! They'll french kiss you for this; I guarantee it. ;)

Here is a link to my thread on flashkit that has more details:
http://board.flashkit.com/board/showthread.php?t=781349