#Alternate Tilesheets

3 messages · Page 1 of 1 (latest)

fierce steppe
#

Edit: Solution found with fishy's help, despite the wiki currently not mentioning it, TileSetSource allows changing .texture. See answers for details.

I've been prototyping a game that would need to have alternate styles for each placed tile, so none of the tile properties change except for the texture.
Imagine the maps of 2D harvest moon games that mostly stay the same, but tiles change their design each season.
Or games where the same scene is playable in different weathers/daytime, making some changes to the tile sheet.

So far I haven't found a reasonable way to do this

  • separate tilesets/atlases means I'd have to give properties like collision and custom data, which becomes pretty unrealistic to keep consistent and avoid mistakes for large tilesets
  • I also looked into tile proxy and take_over_path, but neither seems to fix this issue far as I can see
  • only thing I can think of is to have the alternate tilesets generated on launch to copy all properties from the original except the texture, then iterate over the tilemap whenever something changes to swap out all tiles to the corresponding ID on the other sheet. But that's a lot of relatively slow GDScript code so I'm not really happy with this option either.
  • Godot 3 had tile_set_texture which seems like it would've worked, but that no longer exists in Godot 4 by the looks
formal fjord
#

I think you should be able to do this by setting the texture in the TileSetAtlasSource like this (assuming you have a variable called season that stores the season as an int):

# At the top with the rest of the game logic variables
# Put the paths you want here in the node inspector
@export season_texture_paths: Array[String] = []
var season_image_textures: Array[ImageTexture] = []

# Under _ready():
  for path in season_texture_paths:
    season_image_textures.append(ImageTexture.create_from_image(Image.load_from_file(seasonal_textures[season])))

# Where you set the texture
$MyTileMap.tile_set.get_pattern(0).texture = season_image_textures[season]

Also note that a single TileSet can have multiple sources, so make sure that the int in the get_pattern(0) call is the correct source. If you have just one source 0 should be correct.

fierce steppe
#

alright so the above didn't quite work in my case since I'd need my entire map to be a pattern then, but it did lead me to figuring out the solution, which is quite similar.

Instead of changing a specific pattern, I needed to change the texture of a source.
so

$MyTileMap.tile_set.get_source(0).texture = season_image_textures[season]

worked fine.

I was just confused because the wiki doesn't show .texture as being exposed in a TileSetSource, but testing it in code I can indeed just set the texture and it works perfectly. (note for anyone else using this: it won't refresh the already loaded tilemap. No issue in my case, because it only updates on scene-changes anyway, but if you want to change it while in a scene you'd have to reload the tilemap)