Multidimensional Arrays in AS3
So let’s say you’ve started work on your latest awesome game, and you’ve come up with this level design:
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:
We could just store it in a simple Array , like this:
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:
var level:Array = new Array( 5 ); //there are five tiles level.push( STONE, WATER, WATER, WATER, DIRT ); |
…or this:
var level:Array = new Array( STONE, WATER, WATER, WATER, DIRT ); |
…or even just like this:
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:
…then I can write how this would work in code:
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?
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…
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:
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:
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:
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:
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:
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: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.
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 :