Debug menu, reorganized game scene

This commit is contained in:
gamer147
2026-04-05 20:53:04 -04:00
parent eb5bf32bb8
commit 1973d93b16
17 changed files with 816 additions and 1 deletions

View File

@@ -0,0 +1,145 @@
# F1 Debug Menu Design
## Overview
An F1-toggled debug menu overlay that works regardless of the current scene. Introduces a new root scene (`game.tscn`) that hosts both the debug menu and the active game scene as children. The game pauses underneath while the debug menu is open.
## Scene Tree Structure
```
Game (Node, process_mode = PROCESS_MODE_ALWAYS)
├── DebugMenu (CanvasLayer, layer 100)
│ ├── Panel (PanelContainer)
│ │ ├── SceneList (VBoxContainer of Buttons)
│ │ └── CommandInput (LineEdit)
│ └── ResultLabel (Label, brief flash for command output)
└── ActiveSceneContainer (Node)
└── <currently loaded scene>
```
- `Game` is the new main scene, replacing `strategy_phase.tscn` as the entry point in `project.godot`.
- `DebugMenu` uses a high `CanvasLayer` (layer 100) so it always renders above the active scene.
- `ActiveSceneContainer` is a plain `Node` whose child gets swapped when changing scenes.
- `Game` has `process_mode = PROCESS_MODE_ALWAYS` so it can receive F1 input even while the tree is paused.
## Responsibilities
### Game (`game.gd`)
Thin shell only:
- F1 input toggles `DebugMenu` visibility.
- When debug menu opens: sets `ActiveSceneContainer.process_mode = PROCESS_MODE_DISABLED`.
- When debug menu closes: sets `ActiveSceneContainer.process_mode = PROCESS_MODE_INHERIT`.
- Loads the default scene (strategy_phase) into `ActiveSceneContainer` at startup.
- Passes a reference to `ActiveSceneContainer` to `DebugMenu` at `_ready()`.
### DebugMenu (`debug_menu.gd`)
Owns all debug functionality:
- **Scene registry**: hardcoded array of scene entries.
- **Scene swapping**: frees old child of `ActiveSceneContainer`, instantiates new scene, applies setup if present.
- **Command console**: parses input, dispatches to registered commands or falls back to expression eval.
- **Command registration**: holds an explicit `Array[ConsoleCommand]` populated at `_ready()`.
## Scene Swapping
### Registry Format
A hardcoded array in `DebugMenu`:
```gdscript
var scene_registry: Array = [
{ "name": "Strategy Phase", "path": "res://scenes/strategy_phase.tscn" },
{ "name": "Strategy Phase (Test Data)", "path": "res://scenes/strategy_phase.tscn", "setup": "test_data" },
{ "name": "Main Menu", "path": "res://scenes/main_menu.tscn" },
{ "name": "Visual Novel", "path": "res://scenes/vn_scene.tscn" },
{ "name": "Dialogue", "path": "res://scenes/dialogue_scene.tscn" },
]
```
### Swap Flow
1. Free the current child of `ActiveSceneContainer`.
2. Instantiate the new scene from `path` and add as child.
3. If the entry has a `"setup"` key, call a setup method on `DebugMenu` that applies that configuration to the new scene instance.
4. Close the debug menu and signal `Game` to unpause.
### Setup Hooks
Setup functions live in `DebugMenu`, dispatched by matching the `"setup"` string key. This keeps test configurations self-contained within the debug system.
## Command Console
### Input
A `LineEdit` at the bottom of the debug panel. On Enter:
1. Split input text — first token is the command name, rest are arguments.
2. Check against registered commands by matching `get_command_name()`.
3. If found, call `run()` with args and context.
4. If no match, fall back to Godot's `Expression` class (evaluated with the active scene as base instance).
5. Show the result (or error) in `ResultLabel`, then hide it after 2 seconds using a `Timer` or `create_tween()`.
### Command Pattern
Base class:
```gdscript
class_name ConsoleCommand
func get_command_name() -> String:
return ""
func get_help_text() -> String:
return ""
func run(args: Array, context: Dictionary) -> String:
return ""
```
Each command extends `ConsoleCommand` and overrides these three methods. The `context` dictionary provides access to the active scene container, debug menu reference, and other shared state without coupling commands to specific nodes.
Commands are explicitly registered in an `Array[ConsoleCommand]` in `DebugMenu._ready()`.
### Starter Commands
- **`help`** — lists all registered commands with their help text.
- **`swap <name>`** — scene swap by name (matches against registry entry names).
- **`list_scenes`** — prints available scene registry entries.
### Expression Eval Fallback
Uses Godot's `Expression` class. The expression executes with the current active scene as the base instance, allowing direct access to nodes and properties in the loaded scene. Errors are displayed in `ResultLabel`.
## File Organization
```
nodes/
├── game.gd # Thin shell
├── debug_menu.gd # Scene registry, command console, swap logic
resources/resource_definitions/
├── console_command.gd # Base class
resources/console_commands/
├── swap_command.gd
├── help_command.gd
├── list_scenes_command.gd
scenes/
├── game.tscn # New root scene (new main_scene in project.godot)
prefabs/
├── debug_menu.tscn # CanvasLayer with panel, buttons, input, result label
```
Existing scenes are unchanged — they are loaded as children of `ActiveSceneContainer` instead of being the root.
## Key Decisions
- **No autoload**: The debug menu is a UI node, not a headless service. The `XXXServer` autoload pattern is reserved for game services like a future `SceneManagerServer`.
- **Explicit command registration**: Commands are listed in an array rather than auto-discovered from a folder. Simpler and more readable for a small number of commands. Can be swapped to auto-discovery later if needed.
- **Single-line output**: `ResultLabel` shows one result at a time with a brief display. No scrollable history for now.
- **Hardcoded scene list**: Entries can carry setup data/context, which auto-discovery from `.tscn` files wouldn't support.