Quick answer: Set the HUD CanvasLayer.layer to at least 1 (default is 0). Layer ordering wins over z_index — even a TileMap with z_index 100 sits below a CanvasLayer with layer 1.
You drop a label into a CanvasLayer, parent it to the root, and run the game. The TileMap is rendering over the top of the label. You bump z_index on the label. Nothing changes. You bump it to 1000. Still hidden. The reason is that layer beats z_index in Godot’s 2D ordering rules — and the layer defaults to 0.
The Three-Tier Sort Order
Godot 2D drawing is sorted in this order:
- CanvasLayer.layer — higher draws later (on top). Default 0.
- Node z_index — within a layer, higher draws later. Default 0.
- Scene tree order — within the same z_index, later siblings draw on top.
This means a TileMap with z_index 5 on layer 0 will draw below any node on layer 1, regardless of z_index. The layer index trumps the z_index.
The Fix
Open the HUD CanvasLayer in the scene tree, select it, and in the Inspector set Layer to 1 (or higher):
# hud.tscn structure
HUD (CanvasLayer)
layer = 1 # the critical value
follow_viewport_enabled = false
ScoreLabel (Label)
HealthBar (TextureProgressBar)
Layers can be negative. A common pattern is:
-1— parallax backgrounds0— world (TileMap, entities, props)1— HUD2— modal dialogs and pause menus3— tooltips and notifications
When the TileMap Itself Sets a z_index
If you set z_index on the TileMap to a large positive value (sometimes done to layer ground tiles above props), this only affects nodes on the same CanvasLayer. It cannot push the TileMap above a different CanvasLayer. A common confusion: developers set TileMap z_index to 100 to overlap entities, then later wonder why their HUD on layer 1 still wins. It always will.
When You Have Multiple HUDs
For a pause menu that should cover the HUD when active, give it a higher layer:
# pause_menu.tscn
PauseMenu (CanvasLayer)
layer = 2
process_mode = Node.PROCESS_MODE_ALWAYS # runs while paused
When the player resumes, set the CanvasLayer’s visible = false — or queue_free it — rather than swapping layers, which would be confusing to maintain.
follow_viewport_enabled and Parallax
CanvasLayer has a follow_viewport_enabled property. With it off (default), the layer ignores the camera entirely — perfect for HUDs. With it on, the layer follows the viewport but with a configurable scale, giving you a fast parallax effect. Keep HUD layers with follow_viewport_enabled = false so they never appear to scroll when the camera moves.
Verifying
Toggle the HUD CanvasLayer’s visibility in the editor. The TileMap should draw normally with it off; the HUD should sit cleanly on top with it on. If the HUD still looks clipped or sandwiched, look for a third CanvasLayer in your scene (sometimes added implicitly by a parent autoload like a transition fader) with a higher layer index.
“Layer beats z_index. z_index beats tree order. Once you internalize that, half your draw-order bugs disappear.”
Adopt the −1/0/1/2/3 layer convention project-wide — future-you will appreciate it.