Multidimensional Arrays in AS3

by Michael James Williams on January 13, 2010 · 62 comments

in Articles,AS3 Concepts Explained

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();    //no tiles yet
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 and level[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 STONE, level[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 sure column 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?

{ 61 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';

Roland October 3, 2011 at 6:01 am

Hi! How i could add a mouse event.CLICK to each of those graphics, which are placed on the stage using these methods?

And after i have been clicked, then check what have i clicked and after that trace something or something like that.

Thank.

patrik October 3, 2011 at 1:37 pm

Love this page. Return to it often. Thanks

FIRECREATURE January 29, 2012 at 2:54 pm

Very useful post. Thanks.

TJenner2 February 9, 2012 at 2:46 pm

@ROLAND

I think you want to look at this site here:
http://www.learningactionscript3.com/2008/05/17/grids-arranging-clips/

It explains how to do grids in ActionScript 3.0 which is nothing like it was in 2.0

Eddie J February 21, 2012 at 5:08 pm

Thank you for writing this. It’s always a little confusing for me when working with multidimensional arrays. Also, this is how to define a 2D array

var _myArr:Array = [[],[]];

Cheers

jeetendra singh September 3, 2012 at 7:42 am

var level:Array = new Array( 5 );    //there are five tiles
level.push( STONE, WATER, WATER, WATER, DIRT );

this code will not produce same result as other snippet it will produce 10 element array (not 5)

am i wrong?

Michael James Williams September 3, 2012 at 8:54 am

Jeetendra: you are correct. Oops.

Juliorob December 29, 2012 at 8:42 pm

Thanks, this helped me a lot. You presented the solution very clearly and clean, keep it up.

Ivan July 10, 2013 at 6:16 pm

var squares:Array = new Array(new Array());
//Add a square
squares[x][y] = new square_object();
addChild(squares[x][y]);

moneyisshame July 25, 2013 at 3:19 pm

for 3D is it?:

 //start creating 2D z = 0
var firstRow:Array = [STONE, WATER, WATER, WATER, DIRT]; // y = 0
var secondRow:Array = [STONE, WOOD, WOOD, WOOD, DIRT];// y = 1
var thirdRow:Array = [STONE, STONE, WATER, WATER, DIRT]; //y = 2
var fourthRow:Array = [STONE, WATER, WATER, DIRT, DIRT];//y = 3
//stop creating 2D z = 0  x = 0       x = 1       x=2       x=3    x=4
var z0 = [firstRow, secondRow, thirdRow, fourthRow];

//start creating 2D z = 1
var firstRowZ:Array = [AIR, AIR, AIR, AIR, PLAYER]; // y = 0
var secondRowZ:Array = [STAIR, WOOD, WOOD, WOOD, STAIR];// y = 1
var thirdRowZ:Array = [AIR, CHEST, AIR, AIR, AIR]; //y = 2
var fourthRowZ:Array = [AIR, AIR , AIR, GEM, AIR];//y = 3
//stop creating 2D z = 1 x = 0 x = 1 x=2 x=3 x=4
var z0 = [firstRowZ, secondRowZ, thirdRowZ, fourthRowZ];

//start creating 2D z = 2
var firstRowZ2:Array = [AIR, AIR, AIR, AIR, AIR]; // y = 0
var secondRowZ2:Array = [AIR, AIR, LADYBUG, AIR, AIR];// y = 1
var thirdRowZ2:Array = [AIR, AIR, AIR, AIR, AIR]; //y = 2
var fourthRowZ2:Array = [AIR, AIR, AIR, AIR, AIR];//y = 3
//stop creating 2D z = 2 x = 0 x = 1 x=2 x=3 x=4
var z2 = [firstRowZ2, secondRowZ2, thirdRowZ2, fourthRowZ2];

var myLevel:Array = [z0,z1,z2];

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

{ 1 trackback }

Previous post:

Next post: