Wednesday, 7 December 2011

Action Script


Multidimensional Arrays in AS3

by MICHAEL JAMES WILLIAMS on JANUARY 13, 2010 · 54 COMMENTS
So let’s say you’ve started work on your latest awesome game, and you’ve come up with this level design:
screenshot
Graphics taken from Danc’s Miraculously Flexible Game Prototyping Tiles , which are awesome and free!
How are you going to store this map layout in code?

The One-Dimensional Case

If we just had a single line of tiles, it’d be easy:
screenshot
We could just store it in a simple Array , like this:
? View Code ACTIONSCRIPT3
var level:Array = new Array( 5 );    //there are five tiles
level[0] = STONE;
level[1] = WATER;
level[2] = WATER;
level[3] = WATER;
level[4] = DIRT;
…or like this:
? View Code ACTIONSCRIPT3
var level:Array = new Array( 5 );    //there are five tiles
level.push( STONE, WATER, WATER, WATER, DIRT );
…or this:
? View Code ACTIONSCRIPT3
var level:Array = new Array( STONE, WATER, WATER, WATER, DIRT );
…or even just like this:
? View Code ACTIONSCRIPT3
var level:Array = [STONE, WATER, WATER, WATER, DIRT];
All those code snippets do the same thing.
Then, when we want to find out what tile to place at each position, we can just look up the value of the element of the level array at that index. So, level[0] will be equal to STONE,level[3] will be WATER, and so on.
It’s difficult to imagine how it could be simpler. So how can we do this for a 2D map?

There is No Native 2D Array Class

In other programming languages (like C#, for example ) , we could just create a 2D array which works in the same way as the regular array. So, if I label the rows and columns of the level design I posted above:
screenshot
…then I can write how this would work in code:
? View Code ACTIONSCRIPT3
var level:Array = new Array( 4, 5 );    //there are 4 rows and 5 columns
 
level[0,0] = STONE;
level[0,1] = WATER;
level[0,2] = WATER;
level[0,3] = WATER;
level[0,4] = DIRT;
 
level[1,0] = STONE;
level[1,1] = WOOD;
level[1,2] = WOOD;
level[1,3] = WOOD;
level[1,4] = DIRT;
 
level[2,0] = STONE;
level[2,1] = STONE;
level[2,2] = WATER;
level[2,3] = WATER;
level[2,4] = DIRT;
 
level[3,0] = STONE;
level[3,1] = WATER;
level[3,2] = WATER;
level[3,3] = DIRT;
level[3,4] = DIRT;
Like before, we can look at individual elements in the array; for example, level[1,3] is equal to WOOD and level[2,0] is STONE.
But we cannot do this in AS3! There is no built-in 2D array class. If you write:
var level:Array = new Array( 4, 5 );
…then Flash will just make a new regular, one-dimensional array with level[0] equal to 4 andlevel[1] equal to 5.

The Solution: Nested Arrays

We know we can store an entire single row in an array, so why not just make four arrays, and store one row in each?
? View Code ACTIONSCRIPT3
var firstRow:Array = [STONE, WATER, WATER, WATER, DIRT];
var secondRow:Array = [STONE, WOOD, WOOD, WOOD, DIRT];
var thirdRow:Array = [STONE, STONE, WATER, WATER, DIRT];
var fourthRow:Array = [STONE, WATER, WATER, DIRT, DIRT];
And there’s nothing to stop us putting arrays inside another array, so…
? View Code ACTIONSCRIPT3
var level:Array = [firstRow, secondRow, thirdRow, fourthRow];
Now, level is an array of arrays. We call this “nesting arrays”, and we call each of firstRow,secondRow etc. “nested arrays”.
This means that level[0] is actually an array itself; level[0] is equal to [STONE, WATER, WATER, WATER, DIRT]. And we can access elements within this sub-array — so, level[0][0] is equal to STONElevel[0][3] is WATER, and so on.
In other words, we can access any element of this array of arrays using level[row][column]. Not bad!
Also, we don’t have to create the individual row arrays separately from the level array. It’s fine to do this:
? View Code ACTIONSCRIPT3
var level:Array = new Array( 4 );    //there are four rows
level[0] = [STONE, WATER, WATER, WATER, DIRT];
level[1] = [STONE, WOOD, WOOD, WOOD, DIRT];
level[2] = [STONE, STONE, WATER, WATER, DIRT];
level[3] = [STONE, WATER, WATER, DIRT, DIRT];
…or even:
? View Code ACTIONSCRIPT3
var level:Array = [ [STONE, WATER, WATER, WATER, DIRT], [STONE, WOOD, WOOD, WOOD, DIRT], [STONE, STONE, WATER, WATER, DIRT],  [STONE, WATER, WATER, DIRT, DIRT] ];

Looping Through Nested Arrays

To loop through nested arrays, we can use (not surprisingly) a nested loop. It looks like this:
? View Code ACTIONSCRIPT3
for ( var row:int = 0; row <= 3; row++ )
{
    for ( var column:int = 0; column <= 4; column++ )
    {
        trace( row, column, level[row][column] );
    } 
}
This would output:
0 0 STONE
0 1 WATER
0 2 WATER
0 3 WATER
0 4 DIRT
1 0 STONE
1 1 WATER
1 2 WATER
…and so on, down to:
3 4 DIRT

Ragged Arrays

Using an array of arrays like this allows us to create ragged arrays — that is, arrays where the rows can be of different lengths.
Suppose we have a level like this:
screenshot
Those aren’t “invisible” tiles and the end of the rows; there are just no tiles there. We can easily store this level like so:
? View Code ACTIONSCRIPT3
var level:Array = new Array( 4 );    //there are four rows
level[0] = [STONE, WATER, WATER, WATER];
level[1] = [STONE, WOOD, WOOD, WOOD, DIRT];
level[2] = [STONE, STONE, WATER, WATER];
level[3] = [STONE, WATER, WATER];
Of course, you’ll get an error if you try to access level[3][4], so watch out for that. It’s a particular problem when looping; the above nested loop code needs to be modified like so:
? View Code ACTIONSCRIPT3
for ( var row:int = 0; row < level.length; row++ )
{
    for ( var column:int = 0; column < level[row].length; column++ )
    {
        trace( row, column, level[row][column] );
    } 
}
Note that instead of checking row <= 4, the outer loop checks row < level.length.level.length is the number of elements in the level array — i.e., the number of rows. Similarly, the inner loop now checks column < level[row].length, i.e. it makes surecolumn is less than the number of tiles in the current row.

3D Arrays

We aren’t restricted to two dimensions. We could use as many dimensions as you like, but anything above 3D becomes hard to draw.
screenshot
Here’s a map with rows, columns, and a third dimension: layers. Can you figure out how we could store it using nested arrays?
{ 53 comments… read them below or add one }
Bret July 11, 2011 at 5:36 am
Is there a way to accomplish this using Object literals?
something like :
public var map = new Object();
map.row1 = 'row1';
map.row1.a = 'Stone';
map.row1.b = 'Stone';

No comments:

Post a Comment