Best way to check tiles in a tilemap?

Hey, I’m making a game involving 2D tilemaps and would like some ideas how to approach a problem.

I’m only just starting but in my game you can walk around and I want the player to interact with the tiles of the world, kind of like this:

When they interact with a tile I want something different to happen depending on what type of tile it was. Basically I want the tiles to belong to different pools say “grass tiles”, “rock tiles”, “water tiles” etc. What is the easiest way I can achieve this?

Right now I have 3 ideas but all of them have their own flaws so if someone smarter than me have a simpler solution I would be very interested.

1. Paint the different pools of tiles on different layers and check against that to determine what should happen. I’d rather not do this because there’ll be a LOT of layers to keep track of and it’s easy to make a mistake and paint on the wrong one when there’s 40 of them.
2. Make every tile a scriptable tile and have them store some identifier. This has a similar issues since you can’t add prefab brushes to the tile palette per se and you’d have to select each brush individually to paint every single tile in the world, super time consuming.
3. (which I’m currently using) Use some type of naming scheme for the tile assets “Tilemap_rock_01”, “Tilemap_forest_03” etc and have the script match against the strings. This does not feel great overall since it’s easy to make a typo and it does not work that well on painted prefabs since I can’t use the same apporach on them as the normal tiles in the tilemap because they’re not really assets and not castable as Tilebase.

Thoughts?

Hmm, not sure. I generate my tilemap via formula so it is real easy to store data for the tiles externally, but since it sounds like you’re painting yours that approach isn’t really that viable.
So, that in mind, perhaps what you need to do is program in the structure. Let’s take each of your approaches:

  1. You’d still paint your field on one layer, then on start have a script go through that 1 layer and build all the other layers as needed for you. You’ll still have to identify for that script each tile type, but will save you from making layer paint errors as the script is doing the layer separation instead of you. Not a great approach though ultimately.
  2. Similarly here you’d paint your tilemap with normal tiles, and build the scriptable tiles to the side. Then on run, you have a script go through and substitute the normal tiles with the scripted tiles in their place.
  3. Inevitably you’re going to need to specify whatever identifier you have specifically, so I assume the issue here is that you’re always using straight strings. In that case, the best method to avoid that is just create a class that is nothing but public constant strings for each type of tile. Now the compiler itself will not let you mess up the names as they have to match a constant name, and you can make that constant name whatever you want that you find easiest enough to work with, as it no longer needs to match the filenames. You can even add public functions to identify members of certain groups of tiles (like all grass tiles, or all bushes, etc), so you only have to code these and get them right the once instead of a whole bunch of times.

I’d probably would go with 3 myself and since you’re already doing that seems of these idea the best improvement, although not necessarily the best way to go

I’m not certain what you mean by your usage of the Prefab Brush here with Scriptable Tiles. The default Grid Brush is able to paint Scriptable Tiles from the Tile Palette without needing to change brushes. Although, if the Tiles were actual GameObjects, that would be a different matter.

2 would be a suitable solution in that case.

An example of 2 could be:

public class ForestTile : Tile
{
}

public class RockTile : Tile
{
}

if (tilemap.GetTile(position) is ForestTile)
{
    // Do Forest Things
}

or

public class TerrainTile : Tile
{
     public int terrainType;
}

var tile = tilemap.GetTile<TerrainTile>(position)
switch (tile.terrainType)
{
    case 1:
        // Do Forest Things
}

3 is also a suitable solution. It is possible to create a list of Forest Tile assets and compare the asset references to check as an identifier.