feat(client): Sprint 6 Touch — z-layer pipeline, cursor, fog, interactions, inventory, stance, radial

Three-scope z-layer rendering pipeline (D-049): world z:0-900 inside
CanvasGroup, insert overlay CanvasLayer 10, UI CanvasLayer 20, modal
CanvasLayer 30. Y-sort contract enforced (entities z_index=0). Reserved
ranges for VFX, airborne, lower floors documented in constants.gd.

Sprint 6 client tickets:
- #429: Cursor state machine — 4 states, 150ms transitions (D-056)
- #430: Fog shader rebuild — 5-layer fragment shader, animated noise (D-059)
- #432: Entity interaction list — vertical multi-verb, insert-styled (D-057)
- #433: World radial menu — 2 spokes, drag-release + click-click (D-058)
- #438: Inventory UI — 3x3 grid, 40x40px, 1-9 hotkeys (D-065)
- #439: Stance indicator — color-coded HUD, C/X keybinds (D-053)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 23:06:03 +01:00
co-authored by Claude Opus 4.6
parent 24cce41379
commit 1fcf08d21f
24 changed files with 2370 additions and 151 deletions
+15 -8
View File
@@ -2,16 +2,25 @@ extends Node2D
# World renderer — manages all visual representation from GameState
# Attached to the World node in main.tscn
# Render order (scene tree): TileMapLayer -> FogOverlay -> Entities
#
# D-049 Z-level rendering pipeline (z-layer-gap-analysis.md):
# FogGroup (CanvasGroup) composites world content:
# FloorTiles (TileMapLayer) — z:0 ground plane
# FloorObjects (Node2D) — z:10 cosmetic detail (placeholder)
# YSortGroup (Node2D, y_sort) — z:100 furniture + entities (all z:0 relative)
# Furniture (Node2D, y_sort) — z:0 placed objects (placeholder)
# Entities (Node2D, y_sort) — z:0 entity sprites (D-033 colors)
# Overhead (Node2D) — z:300 ceiling/upper structure (placeholder)
# FogOverlay (Node2D) — z:900 fog shader (OUTSIDE FogGroup)
@onready var tile_renderer = $TileMapLayer
@onready var tile_renderer = $FogGroup/FloorTiles
@onready var fog_renderer = $FogOverlay
@onready var entity_renderer = $Entities
@onready var entity_renderer = $FogGroup/YSortGroup/Entities
var _last_tick: int = -1
func _ready() -> void:
print("WorldRenderer: Initialized")
print("WorldRenderer: Initialized (D-049 z-stack)")
# Called each frame to update visuals from game state.
# Uses tick-based invalidation — re-renders all layers when a new snapshot arrives.
@@ -25,12 +34,10 @@ func update_from_state() -> void:
if tile_renderer and tile_renderer.has_method("update_tiles"):
if GameState.visible_tiles.size() > 0:
tile_renderer.update_tiles(GameState.visible_tiles)
if fog_renderer and fog_renderer.has_method("register_tile_positions"):
fog_renderer.register_tile_positions(GameState.visible_tiles)
# Update fog overlay from visibility data
# Update fog overlay — shader-based, reads from FogState autoload
if fog_renderer and fog_renderer.has_method("update_fog"):
fog_renderer.update_fog(GameState.visible_positions, GameState.player_position)
fog_renderer.update_fog()
# Update entity sprites
if entity_renderer and entity_renderer.has_method("update_entities"):