TileMap's clip_children does not work
Godot version
Godot 4 beta 17
System information
Windows 11, Vulcan, GTX 1050 TI (driver geforce game ready 528.24)
Issue description
TileMap's clip_children does not work
Steps to reproduce
- Create Tilemap
- Add Sprite2D as a child (or TextureRect)
- Try to use clip_children
Minimal reproduction project
https://github.com/godotengine/godot/issues/84501 Looks to be a duplicated issue
@KoBeWi's comment on my duplicate issue should be noted:
Same issue as https://github.com/godotengine/godot/issues/31413 TileMap uses internal Canvasitems, which affects some rendering features.
It appears that #31413 was fixed and merged. Has anyone tested if that fix addresses this issue as well?
This doesn't seem to be fixed in latest master (86bf8354a06ab7b23a0ff6a81b48fd015e92ac94).
CC @groud @KoBeWi @clayjohn
I don't think this is fixable. The problem is that clip_children relies on the CanvasItem hierachy in the RenderingServer, and each TileMap / TileMapLayer nodes does have several of those (one or more per quadrant). This is done that way for performance reason and cannot be changed.
Internally, the hierarchy looks like this:
- TileMapLayer's built-in CanvasItem -> unused, nothing is drawn there
- Quadrant 0 's internal CanvasItem 0 -> used to draw the tiles on quadrant 0, for the first material found
- Quadrant 0 's internal CanvasItem 1 -> used to draw the tiles on quadrant 0, for the second material found and so on
- Quadrant 1 's internal CanvasItem 0
- Quadrant 2 's internal CanvasItem 0
- Quadrant 3 's internal CanvasItem 0
- etc...
- Child nodes CanvasItems -> this is where child nodes end up in the hierarchy.
Basically, there's nothing drawn on the TileMapLayer's built-in CanvasItem, which make it impossible to clip the children.
I can't think of a way to work this around, so I would probably document somewhere the property won't work (or disable it in the inspector IDK)
Well, I have found a hacky workaround:
- The tileset can be completely transparent, with just collision shapes to leverage the physics aspect of tilemaps (and for easy collision editing).
- Build the actual tilemap outside of Godot (in Tiled in my case) and export it as an image.
- Add the exported image as a child Sprite2D to the tilemap (and align with the physics shapes).
- Set Clip Children on the newly-added Sprite2D and parent everything you need to clip to that sprite instead.
I've also been working around this issue:
- Save the tilemap as a separate scene
- Add a subviewport to the original scene
- Add the tilemap scene as a child of the subviewport
- Apply a viewport texture to a sprite, referencing the tilemap subviewport
- Align the sprite with the original tilemap
- Set clipping mode
- Add clipped children
- Set both clipped children and sprite to identical layers, not relative, and not zero (no idea why this is necessary)
Obviously, not a fun workaround, but it allows you to continue editing the tilemap in godot with realtime updates to the map visuals, physics layers, and mask.
However, this is a common use-case and I wonder if it really is unsolvable based on Godot's architectural choices for CanvasItems and TileMap. It seems like a naive solution might copy the contents of the internal CanvasItems into the TileMapLayer's main CanvasItem. This may not be efficient, but neither are the workarounds that are necessary to overcome this limitation. I would happily accept a yellow warning tooltip - "Clipping TileMaps negates many TileMap rendering optimizations; performance will suffer" - rather than just have the feature totally break as it does today.
However, this is a common use-case and I wonder if it really is unsolvable based on Godot's architectural choices for CanvasItems and TileMap. It seems like a naive solution might copy the contents of the internal CanvasItems into the TileMapLayer's main CanvasItem. This may not be efficient, but neither are the workarounds that are necessary to overcome this limitation. I would happily accept a yellow warning tooltip - "Clipping TileMaps negates many TileMap rendering optimizations; performance will suffer" - rather than just have the feature totally break as it does today.
Whether this is common enough has to be debated, but the solution you describe here shouldn't be too hard to implement. Making clip_children forcing the drawing on the main canvas item sounds like a good idea to me.
This is fixable, imo the best way to do it would to be adding functionality for each tile's properties to have the clip contents property, since they already have most of the other properties of CanvasItem