# as2: map array

53 posts

 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. 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); } } } } ``` 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. 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? 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. 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. ok thx shake! i understand the 2d, but what is 1d array? is it that you have seperate columns that you load seperatly? 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 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. 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 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! 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? it is only the tiles, if i put in a tile into the scene manually it will not fall :S Obviously you have some code somewhere that applies gravity. Post it. ```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; } }``` 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. 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 no need for `_root`, just place the code that creates the tiles in the appropriate spot. the main timeline for example 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;``` if i then have a function in the main timeline called nextlevel, how would i execute that function from my players movieclip? 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 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, and the “outer array” is the instance of Vector. 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. why is lel_obster not banned yet? 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 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?