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 Answers 2

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, 2020 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, 2020 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\$ Nov 14, 2020 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, 2020 at 23:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .