as2: map array

53 posts

Flag Post

so i want to create the level for my map using code, what i dont understand is how i can get something like this:

array level 1
1,1,1,1,1,1
1,0,0,0,0,1
1,0,0,0,0,1
1,0,0,0,0,1
1,1,1,1,1,1

placed on the scene.

 
Flag Post

Assuming you have the data in a 2 dimensional array you can just loop through and create a tile (I’m assuming you are creating tiles) every time you see a 1.

var levelData2D:Array = [[1, 1, 1, 1, 1, 1],
				[1, 0, 0, 0, 0, 1],
				[1, 0, 0, 0, 0, 1],
				[1, 0, 0, 0, 0, 1],
				[1, 1, 1, 1, 1, 1]];

var tileArray:Array;
var tileSize:Number = 50;

function onLoad()
{
	tileArray = new Array();
	
	for (var i:Number = 0; i < levelData2D.length; i++)
	{
		for (var j:Number = 0; j < levelData2D[i].length; j++)
		{
			if (levelData2D[i][j] == 1)
			{
				var tile:MovieClip;
				tile = attachMovie("Tile", "tileObject" + getNextHighestDepth(), getNextHighestDepth(), {_x:(j * tileSize), _y:(i * tileSize)});
				tileArray.push(tile);
			}
		}
	}
}
 
Flag Post

Don’t use a 2D array, it’s 2x more lookups. Just use a 1-Dimensional one and use a formula such as y*columns+width to get the ID of the cell you want. This way you can loop with one loop instead of 2 nested ones.

 
Flag Post
Originally posted by RTL_Shadow:

Don’t use a 2D array, it’s 2x more lookups. Just use a 1-Dimensional one and use a formula such as y*columns+width to get the ID of the cell you want. This way you can loop with one loop instead of 2 nested ones.

I’ve always been curious of this, how much better is it than a 2D array, and would you recommend it for a 1D vector as well opposed to a 2?

 
Flag Post
Originally posted by MossyStump:
Originally posted by RTL_Shadow:

Don’t use a 2D array, it’s 2x more lookups. Just use a 1-Dimensional one and use a formula such as y*columns+width to get the ID of the cell you want. This way you can loop with one loop instead of 2 nested ones.

I’ve always been curious of this, how much better is it than a 2D array, and would you recommend it for a 1D vector as well opposed to a 2?

Using a 2D array you lookup it with level[y][x], so you’re technically doing level[i] twice, so if you are accessing it a lot it can stack up. Unless you cache it to a variable, but even then sometimes you’ll have to access it directly sometimes. And yes, it would be fastest to do a 1-Dimensional fixed length vector.

 
Flag Post

You’d provide a useful interface to work with the map, so you should be able to change the underlying implementation easily later without the need to modify any other code.

So if you cannot wrap your head around the 1D array you can come back to it later, if it’s a bottleneck.

 
Flag Post

ok thx shake! i understand the 2d, but what is 1d array? is it that you have seperate columns that you load seperatly?

 
Flag Post

A 1D array in this instance is used just like a 2D array, except you just use one index to pull up what you want, it works essentially the same, buy just requires a little more work

 
Flag Post

Notably the speed difference between Array and Vector.<*>1 is still more than that between level[x][y] and level[x+w*y].

1 Obviously a properly typed vector is faster still.

 
Flag Post
Originally posted by RTL_Shadow:

Don’t use a 2D array, it’s 2x more lookups. Just use a 1-Dimensional one and use a formula such as y*columns+width to get the ID of the cell you want. This way you can loop with one loop instead of 2 nested ones.


for each (var row:Array in rows) {
    for each (var collumn:int in row) {
        // CODE
    }
}

It will only cause one more (additional, not multiplying) lookup for each row, I don’t think it will cause any trouble

 
Flag Post

could i get more help? i managed to get the code that puts the array on the screen as tiles to work, but when it gets put on screen it gets pulled down! like if its affected by gravity or something!

 
Flag Post
Originally posted by darkjonas8:

could i get more help? i managed to get the code that puts the array on the screen as tiles to work, but when it gets put on screen it gets pulled down! like if its affected by gravity or something!

Is it only the tiles that falls down or everything else too?

 
Flag Post

it is only the tiles, if i put in a tile into the scene manually it will not fall :S

 
Flag Post

Obviously you have some code somewhere that applies gravity.

Post it.

 
Flag Post
onClipEvent(load)
{
	//var declarations which is 0
downGravitySpeed = 0;
upGravitySpeed = 0;
frontSpeed = 0;
backSpeed = 0;
hitGround = 1;
touching = 0;
moving = 0;
//Level arrays

var tileArray:Array;
var tileSize:Number = 36;

var levelData2D:Array = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
				   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
				
//other var declarations
acceleration = 0.2;
downGravityAcceleration = 0.14;//0.3
upGravityAcceleration = 0.4;
maxDownGravitySpeed = 8;//1





tileArray = new Array();
	
	for (var i:Number = 0; i < levelData2D.length; i++)
	{
		for (var j:Number = 0; j < levelData2D[i].length; j++)
		{
			if (levelData2D[i][j] == 1)
			{
				var tile:MovieClip;
				tile = attachMovie("Tile", "tileObject" + getNextHighestDepth(), getNextHighestDepth(), {_x:(j * tileSize), _y:(i * tileSize)});
				tileArray.push(tile);
			}
		}
	}


}


	








onClipEvent(enterFrame)
{
	
	
	
	
if(Key.isDown(Key.DOWN)){
	trace(level1);
}
	//hitground = 1 or 0
	if(_root.ground.hitTest(_x, _y + _height / 2, true)){
	hitGround = 1;
	}else if (_root.ground.hitTest(_x + _width / 2, _y + _height / 2, true)){
		hitGround = 1;
	}else if (_root.ground.hitTest(_x - _width / 2, _y + _height / 2, true)){
		hitGround = 1;
	}else{
		hitGround = 0;
	}
	
	if(hitGround == 1){
		
	if(_root.ground.hitTest(_x, _y + _height / 2 - 1, true)){
		_y -= 1;
	}else if (_root.ground.hitTest(_x + _width / 2, _y + _height / 2 - 1, true)){
		_y -= 1;
	}else if (_root.ground.hitTest(_x - _width / 2, _y + _height / 2 - 1, true)){
		_y -= 1;
	}
	}
	//front and back acceleration 
	if(Key.isDown(Key.RIGHT))
	{
	moving = 1;
	frontSpeed += acceleration;
	}else if (Key.isDown(Key.LEFT)){
    moving = 1;
	backSpeed += acceleration;
	}else{
	moving = 0;
	}
	if (Key.isDown(Key.UP)){
		_y -= 20;
	}
	//front and back speed handling
	_x = _x + frontSpeed;
	_x = _x - backSpeed;
	//up and down gravity handling
   
	//gravity speed limiter
	if(downGravitySpeed > maxDownGravitySpeed){
			downGravitySpeed -= downGravityAcceleration;
		}
	//downgravityspeed value declaration
	
	downGravitySpeed += downGravityAcceleration;
	
    //ground hittest
	
	
	
	
	
		
	//trace touchingground change
	if(touching != hitGround){
          trace(hitGround);
		touching == hitGround;  
     }
	//ground hittest handling
	if(hitGround == 0){
		_y += downGravitySpeed;
		_y -= upGravitySpeed;
		
	}
	if(hitGround == 1){
		downGravitySpeed = 0;
	}

}
 
Flag Post

Your attaching your world (tiles) to your player. whichever way your player moves, so does your world.

attachMovie("Tile", "tileObject" + getNextHighestDepth(), getNextHighestDepth(), {_x:(j * tileSize), _y:(i * tileSize)});

This is equivalent to

this.attachMovie(...); //attach an object to me

You need

_root.attachMovie(...); //attach an object to THE STAGE

And, obviously, you’d need _root.getNextHighestDepth() as well.

 
Flag Post

i switched it to _root.attachmovie but all my tiles gets put in one place! im sorry im im to much of a bother but i dont really understand alot of what is inside the (…) part :S

 
Flag Post

no need for _root, just place the code that creates the tiles in the appropriate spot.
the main timeline for example

 
Flag Post
Originally posted by NineFiveThree:

no need for _root, just place the code that creates the tiles in the appropriate spot.
the main timeline for example

Or that. Either way, scope is important.

Also, remove this bit:

{_x:(j * tileSize), _y:(i * tileSize)}

And after the attachMovie call, use:

tile._x = j * tileSize;
tile._y = i * tileSize;
 
Flag Post

if i then have a function in the main timeline called nextlevel, how would i execute that function from my players movieclip?

 
Flag Post
Originally posted by darkjonas8:

if i then have a function in the main timeline called nextlevel, how would i execute that function from my players movieclip?

You wouldn’t.
It’s not your players concern to control your program.
The player is just part of the game.

The flow of your program would be handled at some central point, say the main timeline.
Your program is in some state, say level one.

If a certain thing happens (boss of level 1 defeted, goal reched, whatever) you change the state of your game, say to level two (or a bonus level or whatever)

The easiest way to do this is via Events. The Event system in As2 is rather shitty, so you have to deal with it.
(As3 is a lot better at this)

Basically speaking, you build a broadcaster (like a tv station). This could be your level for example.
You register your main timeline as a listener (sitting in front of the tv).

If the final boss (for example) is defeated, you broadcast the message “level finished” (the news report that godzilla is dead).

Your main timeline receives that message (watches the news) and can now change the level.
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000756.html

 
Flag Post
I’ve always been curious of this, how much better is it than a 2D array, and would you recommend it for a 1D vector as well opposed to a 2?

First, to summarize the long analysis below:

  • A 2D array will be faster for large arrays where a large majority of cases are sequential, rather than random access.
  • A 1D array will generally be faster for small arrays, or when you need to do a lot of random access.
  • The same applies for vectors.

For Vectors of Ints:


Methodology:

  • Cache-unfriendly: iterating through the “inner array” in the outside loop.
  • Cache-friendly: iterating through the “inner array” in the inside loop.
  • Single-loop: Iterating through with one loop. (Using % and / for 2D access)
  • Backwards: Using (i—>0) instead of (i < 5000) {i++;}, cache-friendly
  • Unrolled xN: Unrolled the inner loop by a factor of N.
  • Both unrolled xN: Unrolled both loops by a factor of N each.
  • Manual-cache: Cache the inner array in the outer loop for 2D array.
  • Optimal iteration: My personal preferred method for iteration. inner loop unrolled x50, cache friendly, forwards, and manual caching for 2D.

Takeaways:

  • It might be worth unrolling your loops in some places.
  • 1D array is roughly 3x as fast for random (non-sequential) access (see: cache-unfriendly test)
  • 2D array is slightly faster for itteration, but only if you cache the inner arrays
  • If you’re doing everything else right, iterating backwards doesn’t really show substantial gain.
  • Single loop is (obviously) faster for a 1D array.
  • Be cache-friendly!

Explanation for noobs:

  • Inner vs Outer array

In a 2D vector, the “inner arrays” are the instances of Vector<type>, and the “outer array” is the instance of Vector<Vector<type>. Similarly for a pseudo-2D array, except there are no actual instances, it’s just an abstraction.

  • Cache-locality

When you access an array for the first time, it’s stored in the RAM. loading things from the RAM takes times (let’s say, 30 cycles). However, modern processors all come with what is called a Cache (sometimes multiple). When you request something from the RAM, the processor actually gets about 1KB (more-or-less: depends on your processor) of adjacent data from RAM, and loads it all into the cache. Caching is done in blocks like this because there is far less overhead. Subsequent attempts to load this data from the RAM will instead load to the cache, which, instead of 30 cycles, takes something on the order of 2-3 cycles. The cache, however, is very small, so only data accessed very recently is available in the cache.

When you have a dense (no empty spaces) 1D array, it’s all stored sequentially in memory. This means, when you attempt to load myArray[1] from the RAM, the first several hundred to thousand elements are cached automatically. Now, if you access myArray[2], myArray[3], etc, you will be accessing already-cached elements, which will be much faster. If, on the other hand, you’re looping through the “outside” arrays on the inside loop, the next elements you access after myArray[1] will be elements like myArray[1001], myArray[2001], myArray[3001], and so on (assuming inner-arrays are length 1000). Since these elements are yet-uncached, each access activates the caching once again. When you finally get back to myArray[2], you will have gone through the whole cache, possibly multiple times, and thus element 2 will no longer even be in the cache.

The long and short of it: If you iterate through the outside-arrays in the inside loop, you’ll have to load every element from the RAM. If you iterate in a cache-friendly way, a large majority (probably >99%) of your accesses will be from the cache, which is considerably faster.

How well a piece of code or a data structure utilizes the cache and minimizes re-caching is known as cache locality.

It’s worth noting that due to inefficiencies of the flash player, the numbers 3 and 30 for access-times aren’t really accurate, though the difference is still significant. (these numbers are relatively accurate for native code)

For a 2D array, a similar principle applies. The only difference is that the individual inner arrays are not necessarily located in adjacent places, so the caching will, in general, not apply between inner-arrays. This isn’t a big deal for larger arrays, but may be worth noting for smaller arrays.

  • Loop-unrolling

Loop unrolling is, simply put, the practice of explicitly doing several iterations of a loop in one pass. In it’s simplest form, looks like this:

//this
for (int i = 0; i < 5; i++) { doThing(i); }
//becomes this
doThing(0); doThing(1); doThing(2); doThing(3); doThing(4);

The unrolling may not necessarily get rid of the entire loop:

//this
for (int i = 0; i < 50000; i++) { doThing(i); }
//becomes this
for (int i = 0; i < 50000; i+=5) {
    doThing(i); 
    doThing(i+1); 
    doThing(i+2); 
    doThing(i+3); 
    doThing(i+4);
}

Unrolling can also be done for loops of unknown size:

//this
for (int i = 0; i < length; i++) { doThing(i); }
//becomes this
var i:Int = 0;
while (i < length-4) {
    doThing(i); 
    doThing(i+1); 
    doThing(i+2); 
    doThing(i+3); 
    doThing(i+4);
    i+=5;
}
while (i < length) { doThing(i); }

I’m not entirely sure why this works in Flash. I was surprised when I saw that it did. Normally, loop unrolling’s biggest benefit has to do with optimal CPU scheduling. A full explanation is probably beyond the scope a forum post, but the long-and-short of it is that the CPU can execute later instructions while it waits for the proper condition to execute earlier ones (such as a value being loaded from RAM) if it knows that the instructions are independent. This probably doesn’t apply to flash, however (though perhaps it does). It may also have something to do with branch prediction which is too complext to explain in this post. It also, of course, reduces the loop overhead significantly, which is probably the most significant point for flash.

  • Caching the inner array

Caching the inner array simply means storing a reference to the inner array in a local variable. This creates a pointer directly to the inner array, so that in the inner loop, you don’t have to do an extra array-access every time you want to get that array. Array-access is slower than accessing a local.

This, obviously, only applies to 2D arrays.

 
Flag Post

why is lel_obster not banned yet?

 
Flag Post
Originally posted by darkjonas8:

why is lel_obster not banned yet?

He keeps making new accounts, like LELO_BSTER_ARMY, LE_LOBSTER_ARMY, LEL_OBSTER_ARMY etc

 
Flag Post
Originally posted by Draco18s:
Originally posted by NineFiveThree:

no need for _root, just place the code that creates the tiles in the appropriate spot.
the main timeline for example

Or that. Either way, scope is important.

Also, remove this bit:

{_x:(j * tileSize), _y:(i * tileSize)}

And after the attachMovie call, use:

tile._x = j * tileSize;
tile._y = i * tileSize;

why would i do this? what does it accomplish?