91 lines
3.8 KiB
Markdown
91 lines
3.8 KiB
Markdown
# ADR-004: Form Switch State Machine Design
|
||
|
||
**Status**: Accepted
|
||
**Date**: 2026-04-27
|
||
**Engine**: Unity 2022.3.62f3c1
|
||
**GDD Requirements Addressed**: Form Switch State Machine (systems-index.md #3)
|
||
|
||
---
|
||
|
||
## Context
|
||
|
||
Form switching is Nightborn's core operation — every switch is a risky commitment action. The state machine must balance "responsive feel" against "decisions have weight." It must also support future switch-speed upgrades from the Skill Tree.
|
||
|
||
## Decision
|
||
|
||
### Four-Phase Linear State Machine
|
||
|
||
```
|
||
RequestSwitch(Wolf)
|
||
Idle ─────────────────────────────→ Windup
|
||
↑ │
|
||
│ timer >= recovery │ timer >= windup
|
||
│ │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ Hit during Windup → │←──│
|
||
│ │ OnSwitchInterrupted │ │
|
||
│ └─────────────────────────────┘ ↓
|
||
│ Switching (i-frames)
|
||
Recovery ←───────────────────────────┘
|
||
timer >= switch
|
||
```
|
||
|
||
### Phase Parameters (baseline, modifiable by Skill Tree)
|
||
|
||
| Phase | Duration | Can Act | Interruptible | Can Re-Switch |
|
||
|-------|----------|---------|---------------|---------------|
|
||
| **Idle** | — | Full | — | — |
|
||
| **Windup** | 0.25s | Cannot attack | Yes (hit → lose Blood Energy) | No |
|
||
| **Switching** | 0.10s | Cannot act | No (i-frames) | No |
|
||
| **Recovery** | 0.15s | Can attack/move | No | No |
|
||
|
||
**Total switch time**: 0.50s. Danger window: 0.25s (Windup).
|
||
|
||
### Interrupt Rules
|
||
|
||
- Hit during Windup → `OnSwitchInterrupted` → Blood Energy already spent, switch fails → return to Idle
|
||
- This IS the "switched at the wrong time" punishment — core to the Switch is Commitment pillar
|
||
|
||
### Post-Switch Cooldown
|
||
|
||
After Recovery ends, an additional 0.3s cooldown before another switch is allowed (minimum 0.8s between switches) — prevents switch spam and preserves rhythmic feel.
|
||
|
||
### Implementation
|
||
|
||
```csharp
|
||
// L0 — Pure C#, zero Unity
|
||
public class FormSwitchStateMachine
|
||
{
|
||
public FormType CurrentForm { get; private set; } = FormType.Human;
|
||
public SwitchPhase Phase { get; private set; } = SwitchPhase.Idle;
|
||
public float PhaseTimer { get; private set; }
|
||
|
||
// Tunable (Skill Tree can modify)
|
||
public float WindupDuration = 0.25f;
|
||
public float SwitchDuration = 0.10f;
|
||
public float RecoveryDuration = 0.15f;
|
||
public float CooldownDuration = 0.3f;
|
||
|
||
public SwitchResult RequestSwitch(FormType target, BloodEnergyEconomy energy);
|
||
public void Update(float deltaTime);
|
||
public void Interrupt();
|
||
|
||
public event Action<FormType, FormType> OnFormChanged;
|
||
public event Action<SwitchPhase> OnPhaseChanged;
|
||
public event Action<FormType> OnSwitchInterrupted;
|
||
}
|
||
```
|
||
|
||
### Why a Simple Linear FSM
|
||
|
||
- 4 phases progress sequentially — no Hierarchical FSM or Behavior Tree needed
|
||
- Only Idle accepts input — logic is straightforward for external developers
|
||
- If a future form needs a different flow, it can subclass with its own state machine
|
||
|
||
## Consequences
|
||
|
||
- Switch feel is controlled by exactly 4 parameters (WindupDuration, SwitchDuration, RecoveryDuration, CooldownDuration) — tuning is centralized
|
||
- Interrupt during Windup creates clear "wrong time to switch" punishment, reinforcing Switch is Commitment
|
||
- Skill Tree can directly modify these 4 parameters for switch-speed upgrades
|
||
- Windup duration (0.25s) is the critical feel parameter — MUST be validated through prototype, likely iterating between 0.15s–0.35s
|