# 5. Sub-State Machines for Combat / Locomotion
Part of [[Animation Advanced]]. Prev: [[4.MatchTarget CrossFade Rebind OverrideController]]. Next: [[6.Animation Events Reliable Patterns]]. Intro: [[2.States Transitions and Parameters]]. Brain: [[Enemy AI State Machine]] · [[Game Programming Patterns (Review)]].
## 5.1 Principle
**Gameplay State** (C# / [[Enemy AI State Machine]]) ≠ **Animator Sub-State Machine**. The brain decides *intent* (Locomotion, AttackWindup, Hitstun). The Animator mirrors with clean Sub-State Machines and a small parameter surface.
Avoid: dozens of Any-State → X transitions. Prefer: entry/exit ports on Sub-State Machines + a few gate bools/triggers.
## 5.2 Suggested graph shape
```
Base Layer
├── Locomotion (Sub-State Machine)
│ Idle ⇄ Move (Blend Tree) ⇄ Sprint
│ → Jump / Fall (optional nested)
├── Combat (Sub-State Machine)
│ Windup → Active → Recovery → (exit to Locomotion)
│ Charged variants…
├── HitReact (Sub-State Machine)
│ Light / Heavy / Knockdown
└── Death (state or SSM)
```
Upper-body **Aim** lives on **layer 1** (part 1 / part 7), not inside Base Combat, so locomotion feet keep moving.
## 5.3 Parameter budget
Keep the Animator API small; expand in code:
| Param | Type | Owner |
|---|---|---|
| `Speed` / `MoveX`/`MoveY` | float | Locomotion |
| `IsGrounded` | bool | Mover |
| `Attack` | trigger | Combat brain |
| `AttackId` | int | Which attack clip/branch |
| `Hit` | trigger | Damage pipeline |
| `HitDir` | float/int | React branch |
| `InCombat` | bool | Gates SSM entry |
| `CanCancel` | bool | Set by events (part 6) |
| `Die` | trigger | |
## 5.4 Entry / exit hygiene
- **Enter Combat SSM** via `InCombat` or `Attack` from Locomotion only when grounded / not dying.
- **Exit** Combat only from Recovery (or cancel window) back to Locomotion — not from Active unless design allows.
- **HitReact** can interrupt Combat via ordered interruption or brain `CrossFade` into Hit SSM when hitstun applies.
```csharp
using UnityEngine;
/// <summary>
/// Thin Animator façade — gameplay state machine calls this, not raw SetTrigger soup everywhere.
/// NOT compiled in Unity.
/// </summary>
public sealed class AnimCombatFacade : MonoBehaviour
{
[SerializeField] Animator animator;
static readonly int SpeedHash = Animator.StringToHash("Speed");
static readonly int AttackHash = Animator.StringToHash("Attack");
static readonly int AttackIdHash = Animator.StringToHash("AttackId");
static readonly int HitHash = Animator.StringToHash("Hit");
static readonly int InCombatHash = Animator.StringToHash("InCombat");
static readonly int CanCancelHash = Animator.StringToHash("CanCancel");
static readonly int DieHash = Animator.StringToHash("Die");
public void SetSpeed(float speed) => animator.SetFloat(SpeedHash, speed);
public void RequestAttack(int attackId)
{
animator.SetInteger(AttackIdHash, attackId);
animator.SetBool(InCombatHash, true);
animator.SetTrigger(AttackHash);
}
public void RequestHit()
{
animator.SetTrigger(HitHash);
}
public void RequestDeath()
{
animator.ResetTrigger(AttackHash);
animator.SetTrigger(DieHash);
}
public bool CanCancel => animator.GetBool(CanCancelHash);
// Animation Events →
public void Anim_OpenCancel() => animator.SetBool(CanCancelHash, true);
public void Anim_CloseCancel() => animator.SetBool(CanCancelHash, false);
public void Anim_CombatExit() => animator.SetBool(InCombatHash, false);
}
```
## 5.5 Interruptible transitions (combat)
1. Windup: usually **not** interruptible by another attack; **is** interruptible by Hit.
2. Active (commit): almost nothing cancels except Hit/Death.
3. Recovery: `CanCancel` true → transition to new Attack or Locomotion.
Author transitions with Interruption Source matching that policy (part 2). Brain may additionally `CrossFade` when `CanCancel` and input buffered.
## 5.6 Nested SSMs vs more layers
| Prefer SSM nesting when… | Prefer new layer when… |
|---|---|
| Same body region, mutually exclusive modes | Simultaneous body regions (feet + arms) |
| One clip owns full body | Masked upper-body aim over locomotion |
| Clarity of mode graph | Independent weights |
Readability for players ([[Level Up! (Review)]]) comes from clear poses — architecture should make those poses reachable, not clever.
## Unverified
- Exact Sub-State Machine entry-state portal UI clicks in your Editor version (workflow stable; labels may differ).
See also (added 2026-11-10): [[Combat Feel and Hit Feedback]] - attack strings, hitboxes, hit-stop and dodge on top of this graph.