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(); //no tiles yet 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 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?
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 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.
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 }
← Previous Comments
Is there a way to accomplish this using Object literals?
something like :
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.
Love this page. Return to it often. Thanks
Very useful post. Thanks.
@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
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
Cheers
this code will not produce same result as other snippet it will produce 10 element array (not 5)
am i wrong?
Jeetendra: you are correct. Oops.
Thanks, this helped me a lot. You presented the solution very clearly and clean, keep it up.
var squares:Array = new Array(new Array());
//Add a square
squares[x][y] = new square_object();
addChild(squares[x][y]);
for 3D is it?:
//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];
← Previous Comments
{ 1 trackback }