godot icon indicating copy to clipboard operation
godot copied to clipboard

TileMap's clip_children does not work

Open qwe3121 opened this issue 2 years ago • 8 comments

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

  1. Create Tilemap
  2. Add Sprite2D as a child (or TextureRect)
  3. Try to use clip_children

Minimal reproduction project

TileMapClipChildren.zip

qwe3121 avatar Feb 02 '23 15:02 qwe3121

https://github.com/godotengine/godot/issues/84501 Looks to be a duplicated issue

CodestarGames avatar Nov 13 '23 03:11 CodestarGames

@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.

BrixsterPlanet avatar Nov 15 '23 05:11 BrixsterPlanet

It appears that #31413 was fixed and merged. Has anyone tested if that fix addresses this issue as well?

dastmo avatar Apr 26 '24 08:04 dastmo

This doesn't seem to be fixed in latest master (86bf8354a06ab7b23a0ff6a81b48fd015e92ac94).

CC @groud @KoBeWi @clayjohn

akien-mga avatar Apr 26 '24 09:04 akien-mga

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)

groud avatar Apr 26 '24 09:04 groud

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.

dastmo avatar Apr 26 '24 11:04 dastmo

I've also been working around this issue:

image

  • 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.

hunterloftis avatar May 06 '24 16:05 hunterloftis

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.

groud avatar May 06 '24 17:05 groud

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

hunterbk avatar May 09 '24 03:05 hunterbk