Transparency Masking TileMapLayer tiles (Clipping?)

Godot Version

4.5

Question

I’m doing a top down game and want to slowly break the tiles stepped on to show the animated gif below the tiles. In most engines I can throw a mask on an object so the alpha takes out part of the texture and change the mask as more ‘damage’ is done. I’ve seen how to manually setup clipping for normal objects, but obviously I need to do this via code and to a TileMapLayer made object. Can I not have nice things and have to avoid TileMapLayer and just make my own tile system?





If you’re only using TileSetAtlasSource (and not TileSetScenesCollectionSource), you can use what’s called “alternative tiles” for the different damage levels:

  • Write some mask shader like normal, for example:
shader_type canvas_item;

uniform sampler2D mask;

void fragment() {
    COLOR *= texture(mask, UV);
}
  • For each tile, create one alternative tile per damage level (create_alternative_tile)
  • Attach the shader to all the TileDatas (get with get_tile_data) and set uniform sampler2D mask to the mask corresponding to their damage levels
  • Now you can set the damage of a tile by setting its alternative tile (using the last parameter of set_cell): tile_map_layer.set_cell(coords, source_id, atlas_coords, damage_level)
An example
# Tile as an example class containing atlas coords
for tile: Tile in tiles:
    for i in range(DAMAGE_STEPS):
        # we start at 1 because there is already an alternative tile '0' by default
        if i >= 1:
            tile_set_atlas_source.create_alternative_tile(tile.atlas_coords, i)

        var tile_data: TileData = tile_set_atlas_source.get_tile_data(tile.atlas_coords, i)
        if tile_data == null:
            push_error("Failed to get tile data of tile at %s for alternative tile %d" % [str(tile.atlas_coords), i])
            return

        var shader_material := ShaderMaterial.new()
        shader_material.shader = shader
        shader_material.set_shader_uniform("mask", masks[i])

        tile_data.material = shader_material

This is all assuming you’re creating the tiles in code, if not I don’t know how one would do it, sorry :confused:

Oh, yes. That seems perfect. I probably won’t get to try it out until Wednesday, but it looks exactly like what I was hoping for. Thanks! I’ll respond when I try it out!

I’m doing this in a TileMapLayer. I used the UI to setup the TileSet source (a *.tres file?), so it’s source_id 0. But I’m not sure how to get access to ‘tile_set_atlas_source’ which I’m guessing is a TileSetAtlasSource. Is there a ‘get’ somewhere that will give me access to it?

Looking around, it appears that I can access the TileSetAtlasSource if I can retrieve the TileSet using TileSet.get_source; however, I think the preload is occurring here in the UI. So if there is a ‘get’ to access this TileSet, I might be golden. Though I guess the other option is up remove this after it makes the .tres file and use preload(“res://*.tres”) instead so I have a variable with it in it?

If you have the TileMapLayer, the TileSet is just one of its properties: tile_set. And then, as you already found out, you can use TileSet.get_source