Add sandbox stage builder scripts and functionality
- Introduced StageGizmos for hover highlighting, selection outlines, and rotation handles in the sandbox stage builder. - Added StageGrid for an optional world-space grid overlay that adjusts with camera panning and zooming. - Implemented StageSelection for geometric hit-testing and selection management of nodes in the sandbox. - Created StageSpawner as a registry-driven factory for spawning terrain, props, and stickmen, allowing for dynamic template management. - Each script includes necessary constants, state management, and public API methods for interaction.
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
# Sandbox Stage Builder
|
||||
## 1. Overview & Objective
|
||||
|
||||
**This Phase (Phase 2)** builds the foundation for the kid‑friendly director sandbox: a **visual stage** where users can place terrain, props, and stickmen using a simple palette, then switch between **Edit Mode** (building) and **Play Mode** (physics simulation). This phase focuses on the **"Stage Builder"** experience, setting the stage for later phases that add character actions and story logic.
|
||||
|
||||
The stage is designed to be **extendable** so that future phases (Action Queue, Triggers, Save/Load) can plug in without major rewrites.
|
||||
|
||||
---
|
||||
|
||||
## 2. Scope
|
||||
|
||||
### 2.1. What’s Included
|
||||
- **Mode Management:** Toggle between `EDIT` (placement/transform) and `PLAY` (physics simulation).
|
||||
- **Object Spawning:** Palette buttons for placing terrain blocks (Ground, Ramp, Step), dynamic props (Crate, Ball), and Stickman rigs.
|
||||
- **Selection & Hover:** Click to select, hover to highlight, and **box selection** for mass operations.
|
||||
- **Transform Gizmos:** Translate and rotate handles for selected objects (visible only in Edit Mode).
|
||||
- **Deletion:** Delete selected objects via the Delete/Backspace key.
|
||||
- **Camera:** Pan (middle‑mouse) and zoom (mouse wheel) with configurable zoom limits.
|
||||
- **Status Bar:** Shows current mode, object count, and selection info.
|
||||
- **Signals:** Core events (`mode_changed`, `object_placed`, `object_selected`, `object_deleted`) for future extension.
|
||||
|
||||
### 2.2. What’s NOT Included (Future Phases)
|
||||
- **Stickman navigation / pathfinding** (Phase 3 — Action Queue)
|
||||
- **Speech bubbles / dialogue** (Phase 3)
|
||||
- **Area triggers / sensors** (Phase 4)
|
||||
- **Scene save/load** (Phase 5)
|
||||
- **Graphical UI polish** (big toggle buttons, icon‑based palette — Phase 5)
|
||||
- **IK foot placement / slope alignment** (post‑Phase 3)
|
||||
|
||||
**Important:** Ramps and stairs can be **placed** and physics (props/ragdolls) will slide on them, but stickmen will **not** autonomously walk up/down them until Phase 3.
|
||||
|
||||
---
|
||||
|
||||
## 3. Architecture
|
||||
|
||||
### 3.1. Scene Hierarchy
|
||||
res://scenes/sandbox_stage.tscn
|
||||
│
|
||||
├── SandboxStage (Node2D) ← Root script (class_name SandboxStage)
|
||||
│ │
|
||||
│ ├── World (Node2D) ← Parent container for ALL spawned objects
|
||||
│ │ (TerrainBlocks, PropBlocks, StickmanRigs)
|
||||
│ │
|
||||
│ ├── GizmoLayer (Node2D) ← Draws selection outlines + transform handles
|
||||
│ │ (visible only in EDIT mode)
|
||||
│ │
|
||||
│ ├── Camera2D ← Pan/zoom camera
|
||||
│ │
|
||||
│ ├── UI (CanvasLayer) ← Overlay UI
|
||||
│ │ ├── TopBar (HBoxContainer)
|
||||
│ │ │ ├── ModeToggle (Button) ← "Edit" ↔ "Play" (basic text)
|
||||
│ │ │ ├── SpawnPalette (HBoxContainer)
|
||||
│ │ │ │ ├── "Ground" (Button)
|
||||
│ │ │ │ ├── "Ramp" (Button)
|
||||
│ │ │ │ ├── "Step" (Button)
|
||||
│ │ │ │ ├── "Crate" (Button)
|
||||
│ │ │ │ ├── "Ball" (Button)
|
||||
│ │ │ │ └── "Stickman" (Button)
|
||||
│ │ │ └── StatusBar (Label) ← "Mode: EDIT | Objects: 12 | Selected: Crate"
|
||||
│ │ └── (Future: Action Timeline, etc.)
|
||||
│ │
|
||||
│ └── Spawner (Node) ← Container for spawner logic (StageSpawner)
|
||||
|
||||
text
|
||||
|
||||
### 3.2. Scripts (Class Names)
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `sandbox_stage.gd` (`class_name SandboxStage`) | Root controller. Manages state, selection, mode, signals. |
|
||||
| `stage_spawner.gd` (`class_name StageSpawner`, `extends RefCounted`) | Registry of spawnable types + factory methods. Reuses `TerrainUtils`, `PropUtils`, `StickmanFactory`. |
|
||||
| `stage_selection.gd` (`class_name StageSelection`, `extends RefCounted`) | Handles hover, click selection, box selection, and selection signals. |
|
||||
| `stage_gizmos.gd` (`class_name StageGizmos`, `extends Node2D`) | Draws and handles translate/rotate gizmos. |
|
||||
|
||||
### 3.3. State Management
|
||||
|
||||
- `enum StageMode { EDIT, PLAY }`
|
||||
- `var current_mode: StageMode` (managed by root script)
|
||||
- `var selected_objects: Array[Node2D]` (primary selection is index 0 for gizmos)
|
||||
- **No global singleton** — all state is local to the `SandboxStage` instance, making it self‑contained and testable.
|
||||
|
||||
### 3.4. Signals
|
||||
|
||||
| Signal | Payload | Emitted When |
|
||||
|--------|---------|--------------|
|
||||
| `mode_changed(mode: int)` | `StageMode` enum | Mode toggle. |
|
||||
| `object_placed(node: Node2D)` | Reference to placed object | After successful spawn. |
|
||||
| `object_selected(nodes: Array[Node2D])` | Array of selected nodes | Selection changes. |
|
||||
| `object_deselected()` | (none) | Selection cleared. |
|
||||
| `object_deleted(nodes: Array[Node2D])` | Array of deleted nodes | After deletion. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Key Features & Design Notes
|
||||
|
||||
### 4.1. Mode Management
|
||||
- Toggle between **EDIT** (build) and **PLAY** (simulate).
|
||||
- In `EDIT`: physics is frozen (`RigidBody2D.freeze = true`), gizmos visible, selection active.
|
||||
- In `PLAY`: physics unfrozen, gizmos hidden, selection disabled.
|
||||
|
||||
### 4.2. Object Spawning
|
||||
- Uses a **registry dictionary** in `StageSpawner` — adding a new object type is as simple as appending an entry (no hard‑coded `match` statements).
|
||||
- **Placement mode:** Click a palette button → next click on the `World` spawns the object.
|
||||
- Repeated placement stays active until user presses **Escape** or clicks a different palette button.
|
||||
- Spawn position uses the mouse world position (projected from the camera).
|
||||
|
||||
### 4.3. Selection (EDIT Mode Only)
|
||||
- **Hover:** Subtle highlight/outline on the object under the mouse.
|
||||
- **Single click:** Selects an object (deselects previous).
|
||||
- **Box selection:** Click + drag on empty space draws a rectangle. Release selects all objects inside.
|
||||
- Hold **Shift** to add to current selection instead of replacing.
|
||||
- **Primary selection:** The first selected object (or the one clicked last) receives the transform gizmos.
|
||||
|
||||
### 4.4. Transform Gizmos (Primary Selection Only)
|
||||
- **Translate:** Cross/directional handle — drag to move the object in world space.
|
||||
- **Rotate:** Circular handle — drag to rotate the object around its center.
|
||||
- Gizmos are implemented as `Area2D` nodes so they intercept mouse events (prevents accidental deselection or spawning).
|
||||
- Gizmos are completely hidden in `PLAY` mode.
|
||||
|
||||
### 4.5. Deletion
|
||||
- Press **Delete** or **Backspace** key to remove all currently selected objects.
|
||||
- Deletion emits `object_deleted` with the list of removed nodes.
|
||||
- Objects are `queue_free()`d — no orphaned nodes.
|
||||
|
||||
### 4.6. Camera
|
||||
- **Pan:** Middle‑mouse drag.
|
||||
- **Zoom:** Mouse wheel.
|
||||
- Zoom min/max are `@export var` constants (`min_zoom = 0.1`, `max_zoom = 6.0`) in the root script, so they can be easily adjusted later.
|
||||
- Camera persists across mode toggles.
|
||||
|
||||
### 4.7. Status Bar
|
||||
- Shows: current mode, total object count, and selected object name/count.
|
||||
- Updates in real time on selection, spawning, deletion, and mode change.
|
||||
|
||||
### 4.8. UI Polish (Future Phase 5)
|
||||
- The Phase 2 UI uses **functional text buttons**.
|
||||
- In Phase 5, these will be replaced with:
|
||||
- A large, graphical **Mode Toggle** (slider/switch style).
|
||||
- An icon‑based **Spawn Palette** with draggable cards (drag‑and‑drop onto the stage).
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
|
||||
### A. Mode Management
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| A1 | A **Mode Toggle Button** switches between `EDIT` and `PLAY`. | Click; label changes. |
|
||||
| A2 | In `EDIT` mode, **all RigidBody2D props are frozen**. | Place a PropBlock → PLAY → falls. Switch to EDIT → freezes. |
|
||||
| A3 | In `PLAY` mode, **gizmos are hidden** and **selection is disabled**. | Select object in EDIT → PLAY → no selection box; clicks do nothing. |
|
||||
| A4 | `mode_changed` signal is emitted on every toggle. | Connect a test print. |
|
||||
|
||||
---
|
||||
|
||||
### B. Object Spawning
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| B1 | Spawn Palette contains: **Ground**, **Ramp**, **Step**, **Crate**, **Ball**, **Stickman**. | UI shows all six. |
|
||||
| B2 | Clicking a palette button **enters placement mode**. | Click "Crate" → click world → crate appears. |
|
||||
| B3 | **Repeated placement** stays active until Esc or different button. | Click "Crate" → click twice → two crates. |
|
||||
| B4 | Uses existing factories: `TerrainUtils`, `PropUtils`, `StickmanFactory`. | Inspect spawned object properties. |
|
||||
| B5 | `object_placed` signal is emitted. | Connect a test print. |
|
||||
|
||||
---
|
||||
|
||||
### C. Selection (Hover, Click, Box‑Select) — EDIT Only
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| C1 | **Hover** highlights the object under the mouse. | Hover over a crate → it glows. |
|
||||
| C2 | **Single Click** selects an object (deselects previous). | Click a crate → selection box appears. |
|
||||
| C3 | **Deselect** by clicking empty space. | Click empty space → selection disappears. |
|
||||
| C4 | Only **one primary selection** for gizmos. | Select crate → click ball → only ball has gizmos. |
|
||||
| C5 | **Box Selection:** Click + drag draws a rectangle; release selects all objects inside. | Drag box around three crates → all selected. |
|
||||
| C6 | **Shift+Box** adds to selection (does not replace). | Select A (click) → Shift+Box-select B & C → A, B, C selected. |
|
||||
| C7 | `object_selected` and `object_deselected` signals are emitted. | Connect and verify. |
|
||||
| C8 | **StatusBar** updates with selection info. | Box-select three crates → status shows "Selected: 3 objects". |
|
||||
|
||||
---
|
||||
|
||||
### D. Transform Gizmos (EDIT Only — Primary Selection)
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| D1 | **Translate handle** appears around the selected object. | Select a crate → see move handle. |
|
||||
| D2 | Dragging translate handle moves the object smoothly. | Drag → crate follows mouse. |
|
||||
| D3 | **Rotate handle** appears around the selected object. | Select a crate → see rotation ring. |
|
||||
| D4 | Dragging rotate handle rotates the object around its center. | Drag ring → crate spins. |
|
||||
| D5 | Gizmos **do not appear** in PLAY mode. | Switch to PLAY → gizmos vanish. |
|
||||
| D6 | Gizmos are **hit‑testable** (clicking them does NOT deselect or spawn). | Click move handle → object stays selected. |
|
||||
|
||||
---
|
||||
|
||||
### E. Deletion (EDIT Only)
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| E1 | Pressing **Delete** or **Backspace** removes selected object(s). | Select a crate → press Delete → gone. |
|
||||
| E2 | **Multiple deletion** works with box selection. | Box-select three crates → Delete → all gone. |
|
||||
| E3 | `object_deleted` signal is emitted (array of nodes). | Connect and verify. |
|
||||
| E4 | No orphaned nodes remain (`queue_free()` called). | Check `World` child count. |
|
||||
|
||||
---
|
||||
|
||||
### F. Camera & Viewport
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| F1 | **Pan:** Middle‑mouse drag pans the view. | Drag → camera moves. |
|
||||
| F2 | **Zoom:** Mouse wheel zooms in/out within `min_zoom`/`max_zoom` (exported). | Scroll within bounds. Edit constants → bounds update. |
|
||||
| F3 | Camera does **not** reset on mode toggle. | Zoom/pan → toggle modes → view persists. |
|
||||
|
||||
---
|
||||
|
||||
### G. Status Bar
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| G1 | StatusBar displays **Mode**, **Object Count**, and **Selection Info**. | Place 5 objects → "Objects: 5". Select one → "Selected: Crate". |
|
||||
| G2 | StatusBar updates in real time. | Click, spawn, delete → label updates instantly. |
|
||||
|
||||
---
|
||||
|
||||
### H. Performance & Stability
|
||||
|
||||
| # | Criterion | How to Test |
|
||||
|---|-----------|-------------|
|
||||
| H1 | Spawning 50+ objects does not drop frames. | Click "Crate" 50 times → observe FPS. |
|
||||
| H2 | Rapid toggling between EDIT and PLAY does not crash. | Toggle quickly → no errors. |
|
||||
| H3 | No `push_warning` or errors in the console during normal use. | Monitor Output panel. |
|
||||
|
||||
---
|
||||
|
||||
### I. Extendability (Design)
|
||||
|
||||
| # | Criterion | Evidence |
|
||||
|---|-----------|----------|
|
||||
| I1 | Adding a new spawnable type requires **no modification** to `SandboxStage` — only a registry entry. | Code review: `StageSpawner` uses a Dictionary, not `match`. |
|
||||
| I2 | `World` can hold **any** `Node2D`‑derived object. | Place a custom node → works. |
|
||||
| I3 | Gizmos use `global_position`/`global_rotation` → work for any object. | Select a TerrainBlock → gizmos appear and move it. |
|
||||
| I4 | Signals provide hooks for future systems (Save/Load, Action Queue, Triggers). | Code review: signals exist for all major events. |
|
||||
| I5 | UI palette is built from data, not hard‑coded buttons. | Adding a button = appending to an array. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Future Considerations
|
||||
|
||||
### 6.1. Ramp / Stair Dynamics
|
||||
| Feature | Phase 2 | Phase 3+ |
|
||||
|---------|---------|----------|
|
||||
| Place ramp/step terrain | ✅ | ✅ |
|
||||
| Props roll/fall on ramps | ✅ (physics) | ✅ |
|
||||
| Ragdoll tumbles on ramps | ✅ (physics) | ✅ |
|
||||
| Stickman **walks up** ramp | ❌ | ✅ (NavigationAgent2D) |
|
||||
| Stickman **navigates** stairs | ❌ | ✅ (NavigationAgent2D + IK) |
|
||||
|
||||
### 6.2. UI Polish (Phase 5)
|
||||
- Replace the text‑based Mode Toggle with a **large, kid‑friendly graphical switch/slider**.
|
||||
- Replace text palette buttons with **icon‑based draggable cards** (drag‑and‑drop onto the stage).
|
||||
- Add tooltips and animations for feedback.
|
||||
|
||||
### 6.3. Box Selection Enhancements (Post‑Phase 2)
|
||||
- Option to **invert** selection (select all except those inside box).
|
||||
- **Lock** selected objects (prevent accidental moves).
|
||||
|
||||
---
|
||||
|
||||
## 7. Summary of Deliverables
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `res://scenes/sandbox_stage.tscn` | The main stage scene. |
|
||||
| `res://scripts/sandbox_stage.gd` | Root controller (`class_name SandboxStage`). |
|
||||
| `res://scripts/stage_spawner.gd` | Spawn registry + factory (`class_name StageSpawner`). |
|
||||
| `res://scripts/stage_selection.gd` | Selection logic (`class_name StageSelection`). |
|
||||
| `res://scripts/stage_gizmos.gd` | Gizmo rendering + interaction (`class_name StageGizmos`). |
|
||||
|
||||
---
|
||||
|
||||
## 8. Acceptance Sign‑Off Checklist
|
||||
|
||||
- [ ] Mode toggle switches between EDIT and PLAY.
|
||||
- [ ] Physics freezes/unfreezes correctly.
|
||||
- [ ] All six spawnable types can be placed.
|
||||
- [ ] Repeated placement works.
|
||||
- [ ] Hover highlights objects.
|
||||
- [ ] Single‑click selection works.
|
||||
- [ ] Box selection works (with Shift add‑to‑selection).
|
||||
- [ ] Translate gizmo works.
|
||||
- [ ] Rotate gizmo works.
|
||||
- [ ] Delete key removes selected objects.
|
||||
- [ ] Camera pans and zooms within configurable limits.
|
||||
- [ ] StatusBar updates correctly.
|
||||
- [ ] All signals are emitted.
|
||||
- [ ] No errors/warnings in console.
|
||||
- [ ] Performance is acceptable (50+ objects).
|
||||
|
||||
---
|
||||
|
||||
*End of Phase 2 Plan*
|
||||
Reference in New Issue
Block a user