85 lines
3.4 KiB
Markdown
85 lines
3.4 KiB
Markdown
# ADR-005: Enemy AI Decision Model
|
|
|
|
**Status**: Accepted
|
|
**Date**: 2026-04-27
|
|
**Engine**: Unity 2022.3.62f3c1
|
|
**GDD Requirements Addressed**: Enemy AI Logic, Boss AI Logic (systems-index.md #4, #5)
|
|
|
|
---
|
|
|
|
## Context
|
|
|
|
Nightborn's enemy AI doesn't need complex tactical reasoning, but has a special requirement: each enemy type must strongly favor a specific form, creating "I need to switch" pressure. MVP scope is 3-5 enemy types. The AI model must be simple to implement, produce predictable behavior, and be easily understood and tested by external developers.
|
|
|
|
## Decision
|
|
|
|
**Use lightweight per-type Finite State Machines. Reject Behavior Trees and Utility AI.**
|
|
|
|
### Base FSM Structure (shared by all enemy types)
|
|
|
|
```
|
|
Idle ──→ Chase ──→ Attack ──→ Cooldown
|
|
↑ │ │
|
|
└────────────────────┴──────────┘
|
|
If too far, return to Chase
|
|
```
|
|
|
|
### Per-Type Differentiation in the Attack State
|
|
|
|
| Enemy Type | Attack Behavior | Encouraged Form | Why |
|
|
|------------|----------------|-----------------|-----|
|
|
| **Swarm** | Many simultaneous small-area hits | Mist | Mist's circular AOE clears groups at once |
|
|
| **Brute** | Slow, high-damage single strike | Human | Human's parry window is clear and precise against it |
|
|
| **Stalker** | Fast rush + point-blank flurry | Wolf | Wolf's rectangular dash collides for a stagger counter |
|
|
| **Shooter** | Ranged projectile barrage from periphery | Mist/Wolf | Mist phases through to close, or Wolf bursts to eliminate |
|
|
| **Boss** | Multi-phase mixed patterns | All forms | Phase transitions require form adaptation |
|
|
|
|
### Why Not Behavior Trees
|
|
|
|
BTs excel at complex decision chains (e.g., FPS cover-shooter AI). Nightborn enemies need only 4 states. The tree's maintenance cost exceeds its value.
|
|
|
|
### Why Not Utility AI
|
|
|
|
Scoring systems produce "optimal" behavior but aren't predictable enough — players can't learn enemy patterns, violating the "Battlefield is Information" pillar.
|
|
|
|
### Implementation
|
|
|
|
```csharp
|
|
// L0 — Pure C#, returns one AICommand per frame
|
|
public enum EnemyStateType { Idle, Chase, Attack, Cooldown }
|
|
|
|
public class EnemyAILogic
|
|
{
|
|
public EnemyTypeConfig Config;
|
|
|
|
public AICommand ComputeAction(EnemyState self, PlayerState player)
|
|
{
|
|
TransitionState(self, player);
|
|
return CurrentState switch
|
|
{
|
|
Idle => ScanForPlayer(player),
|
|
Chase => MoveToward(player),
|
|
Attack => ExecuteAttack(self.AttackPattern, player),
|
|
Cooldown => WaitAndReset(self.CooldownTimer),
|
|
};
|
|
}
|
|
|
|
// Per-type override for unique transition logic
|
|
protected virtual void TransitionState(EnemyState self, PlayerState player) { }
|
|
}
|
|
```
|
|
|
|
### Boss Extension
|
|
|
|
Boss AI extends the base FSM with:
|
|
- `BossPhase` enum (additional state dimension)
|
|
- Phase transition conditions (health thresholds, timer triggers)
|
|
- `OnPhaseChanged` event for L1 VFX/Audio synchronization
|
|
|
|
## Consequences
|
|
|
|
- External developers can understand an enemy's behavior from `EnemyTypeConfig` alone — no need to parse behavior trees
|
|
- Enemy behavior is predictable and learnable — satisfies "Battlefield is Information" pillar
|
|
- Each enemy type's Attack pattern naturally points to one form counter — reinforces "Form is Tactics"
|
|
- If future enemies need more intelligence (cover, coordination), the FSM base can be extended without replacement
|