1
\$\begingroup\$

I'm working on a tile map where each type of tiles has 12 states with 12 different sprites associated with it, what I'm trying to say is that whenever I place a tile let's say a road tile, that tile should adjust itself automatically according to the 4 tiles surrounding it, so for example if the tile above it is a road tile and the tile below it is also a road tile, it should automatically adjust itself into a vertical road tile... there is 12 states a tile can have:

1-closed(not surrounded by any similar tile)

2-horizontal(similar tiles up and down)

3-vertical(similar tiles right and left)

4-open from up and left(similar tiles to the left and above)

5-open from left and down(...)

6-open from down and right(...)

7-open from right and up(...)

8-open from up & left & down(3 similar tiles up, left and down)

9-open from left & down & right(...)

10-open from down & right & up(...)

11-open from right & up & left(...)

12-open from all 4 directions(all surrounding tiles are similar)

the problem is that I don't know how to check for surrounding tiles and choose the right tile state without having a huge mess of if statements and performance waste, and I don't have enough experience with algorithms and data structures to figure it out myself.

how can check all 12 states the fastest way possible ?

thanks!

\$\endgroup\$
2
\$\begingroup\$

Use a binary mapping:

  • Assign the directions N/E/S/W to the numbers 1/2/4/8
  • If the adjacent tile is a road, add that number.
  • Use the resulting number as the tile image.

The map tiles will need to be in the corresponding order. No adjacent roads is tile 0, and 4 adjacent roads is tile 15. If your sprite sheet is laid out correctly this can be coded in a concise and elegant way.

Your 12 states are missing the case where there is a single adjacent road. You need to decide what happens with that, if it's a possible game state (duplicate the closed tile?).

Here's an example from one of my old projects:

var tileMap = new Array(9, 10, 13, 16, 12, 11, 17, 21, 15, 18, 14, 23, 19, 24, 22, 20);
var mapDressing = 0;

function getTileImage(x, y) {
    //in: x,y location of tile
    //out: number of tile for that location
    //known: global tile map
    if (!isWall(getTile(x,y))) {
        return (mapDressing * 54) + 4;
    }
    
    var tileAbove = getTile(x, y-1);
    var tileBelow = getTile(x, y+1);
    var tileLeft = getTile(x-1, y);
    var tileRight = getTile(x+1, y);
    
    var tileAboveContent = 0;
    var tileBelowContent = 0;
    var tileLeftContent = 0;
    var tileRightContent = 0;
    
    if (isWall(tileAbove)) {
        tileAboveContent = 1;
    }
    if (isWall(tileBelow)) {
        tileBelowContent = 1;
    }
    if (isWall(tileLeft)) {
        tileLeftContent = 1;
    }
    if (isWall(tileRight)) {
        tileRightContent = 1;
    }
    
    var tileIndex = tileRightContent + tileBelowContent*2 + tileLeftContent*4 + tileAboveContent * 8;
    
    return (mapDressing * 54) + tileMap[tileIndex];
}
\$\endgroup\$
2
  • \$\begingroup\$ This is the bit manipulation I was talking about for checking at runtime and/or storing the index value at construction, but you still have to iterate through all the neighbors to calculate the index value. \$\endgroup\$ – Casey Nov 28 '20 at 6:38
  • 1
    \$\begingroup\$ Since your values are multiples of 2 you can use bit shifting and you get a little more efficient: tileAboveContent = 1 << 0, tileRightContent = 1 << 1, tileBelowContent = 1 << 2, tileLeftContent = 1 << 3, then bitwise OR the values together: var tileIndex = tileAboveContent | tileRightContent | tileBelowContent | tileLeftContent; \$\endgroup\$ – Casey Nov 28 '20 at 6:47
1
\$\begingroup\$

If you want to change the state of a tile based on its neighbors, you pretty much have to do this. You can calculate the cost up-front during construction if the map doesn't change during the game but it's almost unavoidable to have to iterate through all the neighbors and keep a count.

There are small improvements that can be made using bit manipulation techniques for instant checking, but again, the value representing the neighbors' state still needs to be calculated somehow.

\$\endgroup\$
2
  • \$\begingroup\$ well I guess you're right, I couldn't find any solution after 2 days of thinking after all, alright thank you Casey \$\endgroup\$ – VoId Nov 14 '20 at 23:42
  • \$\begingroup\$ @VoId If this satisfies your question, please mark the question as Answered by clicking the check mark to the left. \$\endgroup\$ – Casey Nov 14 '20 at 23:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.