I am trying to assign some logic via scripts to tiles in a TileMap, like for example tiles that have multiple lives or tiles that reappear after a certain time. Given that such dynamic behavior cannot be done with custom data layers as far as I understand (fixed & same for all tiles), I tried to implement it using Scene Collection TileSet. It seems like there is no way to use all the nice features from the Atlas, like the autotiling. Am I missing something? If not, how would you tackle this problem in the least complicated, most consistent way?
You can’t autotile scenes collection tiles as they are independent scenes that are not aware of they being in a TileMap
For your needs you only need to keep a Dictionary with the cell coordinates as key and whatever data you want to keep for each one.
Example:
extends TileMap
var cells_health = {}
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.pressed:
var cell = local_to_map(get_local_mouse_position())
# If we don't have information about the cell
if not cells_health.has(cell):
# Try to get its TileData
var tile_data = get_cell_tile_data(0, cell)
if tile_data:
# If there's a TileData, try to get the health
var health = tile_data.get_custom_data("health")
if health > 0:
# if health is bigger than 0 then add it to our dictionary
cells_health[cell] = health
if cells_health.has(cell):
# if we have health information then substract 1
cells_health[cell] -= 1
if cells_health[cell] <= 0:
# if it's less than or equal to 0 erase it from the dictionary
# and spawn the tile after a set amount of time
cells_health.erase(cell)
respawn_cell(cell)
func respawn_cell(coords:Vector2i, time:float = 2) -> void:
# Get the current source_id and atlas_coords of the given coordinate
var source_id = get_cell_source_id(0, coords)
var atlas_coords = get_cell_atlas_coords(0, coords)
# erase the cell
erase_cell(0, coords)
# wait for the amount of time
await get_tree().create_timer(time).timeout
# set the cell back
set_cell(0, coords, source_id, atlas_coords)
This is a very good solution for this specific problem. I will probably want a diverse set of cell/tile behaviors in the end. Using a single TileMap, this approach would mean that the TileMap script handles a lot of diverse block behavior. Alternatively, one could have multiple TileMaps for each block type, but that removes some of the advantages of having a TileMap in the first place, I think.
What I opted to do instead is to have a script in the TileMap that puts a Scene representing a block type at the position of its corresponding tile at runtime. It also couples the internal block logic for health to functions for changing or deleting the tile in the TileMap using signals. The behavior of a block can that be kept in separate block scenes. This might of course come with a performance penalty, but I am not planning on placing hundreds of tiles anyway.