- Added a new event-driven system for reactive storytelling, allowing rules like "When X happens, do Y." - Introduced TriggerArea class for placeable sensors in the stage. - Enhanced StickmanRig to emit signals for actions and arrivals. - Updated StageDirectorVisuals to render rules visually with labels and badges. - Modified StageSpawner to support spawning TriggerAreas. - Improved text baseline calculations in speech bubbles and rule labels. - Added tests for text baseline fixes to ensure proper rendering. - Documented the implementation plan for Phase 4 in PHASE_4_TRIGGER_EVENTS.md. - Created a polish plan for Phase 4 in PHASE_4b_POLISH.md.
327 lines
17 KiB
Markdown
327 lines
17 KiB
Markdown
# Phase 4: Triggers & Event System — Implementation Plan
|
|
|
|
## 1. Overview
|
|
|
|
Phase 4 adds **reactive storytelling** to the Sandbox Stage. While Phase 3a gave directors _sequential_ control (actions in a fixed order), Phase 4 gives them _reactive_ control — **"When X happens, do Y."**
|
|
|
|
This unlocks:
|
|
|
|
- **Cross-stickman communication** (Stickman A arrives → Stickman B speaks)
|
|
- **Environmental reactions** (Stickman reaches crate → crate explodes)
|
|
- **Branching narratives** (Arrive at different waypoints → different reactions)
|
|
|
|
**Crucially:** Phase 4 **does not** replace or duplicate the Phase 3a Action Queue. Sequential actions for a single stickman (Walk → Wait → Speak → Walk) remain unchanged. Phase 4 adds **cross-object reactivity**.
|
|
|
|
---
|
|
|
|
## 2. Core Distinction
|
|
|
|
| Feature | Phase 3a (Already Works) | Phase 4 (New) |
|
|
| ----------------------------------------------- | ------------------------ | -------------- |
|
|
| Walk → Wait → Speak → Walk | ✅ Action Queue | ✅ (unchanged) |
|
|
| Waypoint → next action | ✅ Action Runner | ✅ (unchanged) |
|
|
| **Stickman A arrives → Stickman B speaks** | ❌ | ✅ NEW |
|
|
| **Stickman collides with prop → prop explodes** | ❌ | ✅ NEW |
|
|
| **Stickman enters area → all stickmen react** | ❌ | ✅ NEW |
|
|
| **Multiple reactions per event** | ❌ | ✅ NEW |
|
|
|
|
---
|
|
|
|
## 3. The User's Mental Model
|
|
|
|
The director should think of events as **"When → Then"** rules that exist _alongside_ the action queues.
|
|
|
|
- **Action Queue:** "Stickman A walks to the crate, waits, then speaks."
|
|
- **Event Rule:** "When Stickman A reaches the crate, Stickman B says 'Welcome!'"
|
|
|
|
The event rule is **not** part of Stickman A's queue. It's a separate rule that watches Stickman A and reacts independently.
|
|
|
|
---
|
|
|
|
## 4. Milestone Breakdown
|
|
|
|
| # | Milestone | Description |
|
|
| --- | --------------------------- | ------------------------------------------------------- |
|
|
| 4.1 | **Event Data Model** | Define rule structure and storage. |
|
|
| 4.2 | **Trigger System** | Detect and emit events from stickmen, props, and areas. |
|
|
| 4.3 | **Event Rule UI** | Visual rule builder (When → Then workflow). |
|
|
| 4.4 | **Trigger Areas** | Placeable `Area2D` sensors. |
|
|
| 4.5 | **Prop Interaction Events** | Prop collisions emit events. |
|
|
| 4.6 | **Chain Reactions** | Multiple actions per rule, executed in sequence. |
|
|
| 4.7 | **Integration & Polish** | Full end-to-end testing, bug fixes, UI polish. |
|
|
|
|
---
|
|
|
|
## 5. Milestone 4.3: Event Rule UI
|
|
|
|
### 5.1. The "When..." Option
|
|
|
|
```
|
|
The existing action popup is extended with a new section:
|
|
┌─────────────────────────────────────────────┐
|
|
│ 🚶 Walk To │
|
|
│ 💬 Speak │
|
|
│ ⏳ Wait │
|
|
│ 💥 Ragdoll │
|
|
│ 🔄 Recover │
|
|
│ ───────────────────────────────────────── │
|
|
│ ⚡ When... (opens trigger sub-menu) │
|
|
└─────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Design note:** The "When..." option is visually separated (line divider) to signal it creates a _rule_, not a direct action.
|
|
|
|
### 5.2. Trigger Sub-Menu
|
|
|
|
```
|
|
When "When..." is clicked, the popup expands/replaces with trigger types:
|
|
┌─────────────────────────────────────────────┐
|
|
│ 📍 Arrives at a waypoint │
|
|
│ ✅ Completes any action │
|
|
│ 💬 Finishes speaking │
|
|
│ 🎯 Enters trigger area │
|
|
│ 💥 Collides with something │
|
|
│ ⬅ Back to actions │
|
|
└─────────────────────────────────────────────┘
|
|
```
|
|
|
|
Each trigger type corresponds to a signal emitted by stickmen or the stage.
|
|
|
|
### 5.3. The Rule Building Flow (6 Stages)
|
|
|
|
```
|
|
┌──────────────┐
|
|
│ STAGE 1 │ → User clicks stickman → popup opens
|
|
│ IDLE │
|
|
└──────┬───────┘
|
|
│ Click "When..."
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 2 │ → User selects trigger type
|
|
│ SELECT_TRIGGER│
|
|
└──────┬───────┘
|
|
│ (If trigger needs a target: waypoint, area, prop)
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 3 │ → User clicks the specific target
|
|
│ TARGET_ENTRY │ (e.g., a waypoint dot on the stage)
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 4 │ → User selects the action (Speak, Walk, etc.)
|
|
│ SELECT_ACTION│
|
|
└──────┬───────┘
|
|
│ (If action needs a target: a stickman or prop)
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 5 │ → User clicks the target stickman/prop
|
|
│ TARGET_ENTRY2│
|
|
└──────┬───────┘
|
|
│ (If action needs params: text, duration, etc.)
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 6 │ → User fills in params
|
|
│ PARAMS │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ STAGE 7 │ → Rule is stored. Visuals update.
|
|
│ DONE │
|
|
└──────────────┘
|
|
|
|
```
|
|
|
|
**Escape** at any stage cancels rule creation and returns to IDLE.
|
|
|
|
---
|
|
|
|
## 6. Complete UI Walkthrough: "A Reaches Waypoint → B Speaks"
|
|
|
|
### Step 0: Prerequisites (Edit Mode)
|
|
|
|
- Stickman A and Stickman B are placed on the stage.
|
|
- Stickman A already has a **"Walk To"** action queued (with a visible waypoint marker on the stage), OR the user is about to create one.
|
|
|
|
### Step 1: Create Stickman A's Walk (If Not Done)
|
|
|
|
| # | User Action | System Response |
|
|
| --- | -------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
| 1 | Click the **"Direct"** tool button in the palette. | Cursor changes to crosshair. |
|
|
| 2 | Click **Stickman A** on the stage. | Action popup appears. |
|
|
| 3 | Click **"🚶 Walk To"** in the popup. | Popup closes. Stage enters target placement mode. |
|
|
| 4 | Click a spot on the stage. | Blue waypoint dot appears. `walk_to` action added to Stickman A's queue. |
|
|
|
|
### Step 2: Create the Reactive Event Rule
|
|
|
|
| # | User Action | System Response |
|
|
| --- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
| 5 | Click the **"Direct"** tool again (if it was deselected). | Cursor changes to crosshair. |
|
|
| 6 | Click **Stickman A** on the stage. | Action popup appears with new "When..." option. |
|
|
| 7 | Click **"⚡ When..."** | Trigger sub-menu opens. |
|
|
| 8 | Click **"📍 Arrives at a waypoint"** | Popup closes. Cursor changes to target selector. Status bar: _"Click the waypoint you want to trigger on."_ |
|
|
| 9 | Click **the blue waypoint dot** on the stage. | Waypoint glows green briefly. Popup reappears with trigger confirmed. |
|
|
| 10 | Click **"💬 Speak"** | Popup closes. Cursor changes to target selector. Status bar: _"Click the stickman who will speak."_ |
|
|
| 11 | Click **Stickman B** on the stage. | Stickman B glows yellow. Text dialog appears. |
|
|
| 12 | Type **"Hello there!"** and click **[OK]** | Dialog closes. Toast: _"Rule created!"_ |
|
|
|
|
### Step 3: Visual Feedback (Edit Mode)
|
|
|
|
| Element | Appearance | Description |
|
|
| ---------------- | ------------------------------------------- | --------------------------------------- |
|
|
| **Dashed line** | White dashed line | Connects waypoint to Stickman B. |
|
|
| **Label** | _"When arrives → Speak 'Hello there!'"_ | Centered on the line. |
|
|
| **Color coding** | Green waypoint + orange badge on Stickman B | Shows trigger source and action target. |
|
|
| **Rule badge** | ⚡ icon on the label | Hover shows full rule details. |
|
|
| **Delete icon** | ✕ on the label | Click to remove rule. |
|
|
|
|
### Step 4: Test in Play Mode
|
|
|
|
| # | User Action | System Response |
|
|
| --- | ------------------------------------- | ----------------------------------------------------------- |
|
|
| 13 | Click **"Play"** button. | All queues start executing. |
|
|
| 14 | Stickman A walks to waypoint. | Normal Phase 3a behavior. |
|
|
| 15 | When Stickman A arrives, event fires. | Stickman B says **"Hello there!"** (speech bubble appears). |
|
|
|
|
---
|
|
|
|
## 7. Visual Feedback (Edit Mode Only)
|
|
|
|
### 7.1. Rule Visualization Elements
|
|
|
|
| Element | Color/Style | Position |
|
|
| ------------------- | ----------------------------- | ---------------------- |
|
|
| **Trigger badge** | Green, small, "⚡" | Near source object. |
|
|
| **Action badge** | Orange, small, "→" | Near target object. |
|
|
| **Connection line** | Dashed white, alpha 0.6 | From source to target. |
|
|
| **Label** | White text on dark background | Centered on line. |
|
|
| **Waypoint glow** | Green (if trigger source) | On the waypoint dot. |
|
|
|
|
### 7.2. Rule Interaction
|
|
|
|
| Action | Behavior |
|
|
| --------------------- | ----------------------------------------- |
|
|
| **Click rule label** | Opens edit popup for that rule. |
|
|
| **Click delete icon** | Removes the rule (confirmation optional). |
|
|
| **Hover rule label** | Shows tooltip with full rule details. |
|
|
|
|
### 7.3. What the User Sees on the Stage
|
|
|
|
```
|
|
Stickman A Stickman B
|
|
┌──────┐ ┌──────┐
|
|
│ 🔵 │ │ 🔵 │
|
|
│ (A) │ │ (B) │
|
|
└──┬───┘ └──┬───┘
|
|
│ │
|
|
│ ════════════╗ │
|
|
│ (When arrives) │ │
|
|
│ ════════════╝ │
|
|
│ ── ── ── ── ── ── ── ── →│
|
|
│ (Then Speak "Got it!") │
|
|
│ │
|
|
┌──┴──────────────────────────────────┐│
|
|
│ 📍 Waypoint 3 ││
|
|
└──────────────────────────────────────┘
|
|
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Event Data Model
|
|
|
|
### 8.1. Rule Structure
|
|
|
|
Rules are stored in the stage's event registry and have three parts:
|
|
|
|
**Trigger** — The "When" part.
|
|
|
|
| Trigger Type | Source | Target | Description |
|
|
| --------------------- | ------------- | ------------ | ------------------------------------ |
|
|
| `arrived_at_waypoint` | Stickman | Waypoint | Stickman completes a walk. |
|
|
| `action_finished` | Stickman | Action type | Stickman finishes any action. |
|
|
| `speech_finished` | Stickman | (none) | Stickman finishes speaking. |
|
|
| `entered_area` | Stickman/Prop | Trigger Area | Object enters a trigger area. |
|
|
| `collided` | Stickman/Prop | Object | Object collides with another object. |
|
|
|
|
**Action** — The "Then" part.
|
|
|
|
| Action Type | Target | Params |
|
|
| -------------- | -------- | ----------------------------------- |
|
|
| `walk_to` | Stickman | `target` (Vector2) |
|
|
| `speak` | Stickman | `text` (String), `duration` (float) |
|
|
| `wait` | Stickman | `duration` (float) |
|
|
| `ragdoll` | Stickman | (none) |
|
|
| `recover` | Stickman | (none) |
|
|
| `explode_prop` | Prop | (none) — future |
|
|
| `spawn_prop` | Stage | `type` (String) — future |
|
|
|
|
### 8.2. Rule Storage
|
|
|
|
Rules are stored in `SandboxStage._event_rules` and persist across mode toggles (Play ↔ Edit). They are **not** saved to disk in Phase 4 (deferred to Phase 5).
|
|
|
|
### 8.3. Rule Evaluation
|
|
|
|
Rules are evaluated **in order** when an event occurs. If a rule's trigger matches the event, its actions are executed.
|
|
|
|
---
|
|
|
|
## 9. What's NOT in Phase 4
|
|
|
|
| Feature | Why Excluded |
|
|
| ----------------------------------------------------------- | -------------------------------------------------- |
|
|
| "When Stickman A arrives → Stickman A speaks" | This is just a sequential queue action (Phase 3a). |
|
|
| "When Stickman A finishes walking → Stickman A walks again" | Same as above. |
|
|
| Conditions (AND/OR logic) | Too complex for Phase 4; deferred to future. |
|
|
| Variables / counters | Deferred to future. |
|
|
| Save/Load rules to disk | Phase 5. |
|
|
| Edit/Delete actions | Phase 3c. |
|
|
| Stickman/Prop selector grids | Phase 3b. |
|
|
|
|
---
|
|
|
|
## 10. Acceptance Criteria
|
|
|
|
### 10.1. Cross-Stickman Events
|
|
|
|
- [ ] **"When..." option appears** in the action popup.
|
|
- [ ] **Trigger sub-menu opens** when "When..." is clicked.
|
|
- [ ] **Waypoint trigger works:** A arrives → B speaks.
|
|
- [ ] **Action completion trigger works:** A finishes speaking → B walks.
|
|
- [ ] **Speech completion trigger works:** A finishes speaking → B speaks.
|
|
- [ ] **Multiple actions per rule work:** Trigger → B speaks AND C walks.
|
|
|
|
### 10.2. Cross-Object Events
|
|
|
|
- [ ] **Area trigger works:** A enters area → B speaks.
|
|
- [ ] **Prop collision trigger works:** A hits crate → crate explodes.
|
|
- [ ] **Prop reaction works:** Trigger → prop explodes (disappears + particles).
|
|
|
|
### 10.3. UI & Visuals
|
|
|
|
- [ ] **Rule label shows summary:** "When arrives → Speak" text appears.
|
|
- [ ] **Delete icon works:** Click ✕ → rule removed.
|
|
- [ ] **Clicking rule label opens edit popup:** Click label → popup re-opens.
|
|
- [ ] **Rules persist across mode toggles:** Create rule → Play → Edit → rule still there.
|
|
- [ ] **Rules are cleaned up** when source/target objects are deleted.
|
|
|
|
### 10.4. Backward Compatibility
|
|
|
|
- [ ] **Sequential actions still work:** Walk → Wait → Speak → Walk works.
|
|
- [ ] **Existing queues unchanged:** Any Phase 3a scene loads and runs.
|
|
|
|
---
|
|
|
|
## 11. File Changes Summary
|
|
|
|
| File | Changes |
|
|
| ----------------------------------- | ------------------------------------------------------------- |
|
|
| `scripts/sandbox_stage.gd` | Add `_event_rules`, event evaluation, rule UI state machine. |
|
|
| `scripts/stickman_rig.gd` | Emit `arrived`, `action_finished`, `speech_finished` signals. |
|
|
| `scripts/stage_director_visuals.gd` | Draw rule lines, labels, and badges. |
|
|
| `scripts/trigger_area.gd` | NEW: Placeable `Area2D` sensor. |
|
|
| `scripts/prop_block.gd` | Emit `collided` signal. |
|
|
|
|
---
|