← Cheatsheets
Tags: unity, fsm, state-machines, behavior-trees, ai, transitions, blackboard, game-dev
Last updated: 2026-06-27
State Machines (FSM / Behavior Trees) Cheatsheet
Quick Reference
| Approach | Best For | Complexity |
| Enum-based FSM | Simple AI (patrol, chase, attack) | Low |
| Class-based FSM | Medium AI with state data | Medium |
| Animator FSM | Animation-driven behaviour | Low |
| Behavior Tree | Complex AI, modular decision-making | High |
Enum-Based FSM
enum EnemyState { Idle, Patrol, Chase, Attack, Dead }
EnemyState currentState;
void Update() {
switch (currentState) {
case EnemyState.Idle: IdleUpdate(); break;
case EnemyState.Patrol: PatrolUpdate(); break;
case EnemyState.Chase: ChaseUpdate(); break;
case EnemyState.Attack: AttackUpdate(); break;
case EnemyState.Dead: DeadUpdate(); break;
}
}
void TransitionTo(EnemyState newState) {
ExitState(currentState);
currentState = newState;
EnterState(newState);
}
void ExitState(EnemyState state) { /* cleanup */ }
void EnterState(EnemyState state) { /* setup */ }
State-Specific Logic
void IdleUpdate() {
idleTimer -= Time.deltaTime;
if (idleTimer <= 0) TransitionTo(EnemyState.Patrol);
if (SeePlayer()) TransitionTo(EnemyState.Chase);
}
void ChaseUpdate() {
MoveTowards(player.position);
if (DistanceTo(player) < attackRange)
TransitionTo(EnemyState.Attack);
if (!SeePlayer())
TransitionTo(EnemyState.Patrol);
}
Class-Based FSM
public abstract class State {
public abstract void Enter();
public abstract void Update();
public abstract void Exit();
}
public class StateMachine : MonoBehaviour {
State currentState;
public void ChangeState(State newState) {
currentState?.Exit();
currentState = newState;
currentState?.Enter();
}
void Update() => currentState?.Update();
}
Concrete States
public class PatrolState : State {
Enemy owner;
public PatrolState(Enemy e) => owner = e;
public override void Enter() => owner.SetDestination(RandomWaypoint());
public override void Update() {
if (owner.ReachedDestination()) owner.SetDestination(RandomWaypoint());
if (owner.SeesPlayer()) owner.machine.ChangeState(new ChaseState(owner));
}
public override void Exit() => owner.StopMoving();
}
Animator FSM (Unity Mecanim)
| Feature | How |
| States | Animation clips or Blend Trees |
| Transitions | Arrow between states with conditions |
| Parameters | Float, Int, Bool, Trigger |
| Layers | Separate state machines (e.g. upper/lower body) |
| Sub-State Machines | Nested FSMs for organisation |
| Blend Trees | Blend between animations by parameter |
Animator anim = GetComponent<Animator>();
anim.SetFloat("Speed", velocity.magnitude);
anim.SetBool("IsGrounded", isGrounded);
anim.SetTrigger("Jump");
anim.SetInteger("State", (int)currentState);
Animator Transition Conditions
| Type | Example |
| Float (Greater/Less) | Speed > 0.1 |
| Bool (True/False) | IsGrounded = true |
| Trigger | Jump (auto-resets) |
| Int (Equals/Greater/Less) | Health <= 0 |
| Exit Time | After 0.8 normalised time |
| Has Exit Time | Transition at exact frame |
Behavior Trees
Core Nodes
| Node | Role |
| Selector (OR) | Try children left-to-right until one succeeds |
| Sequence (AND) | Run children left-to-right until one fails |
| Condition | Check a condition (succeed/fail) |
| Action | Perform an action (returns Running/Success/Fail) |
| Decorator | Modify child behaviour (invert, repeat, cooldown) |
Evaluation Flow
Selector
├── Sequence (Attack)
│ ├── Condition: EnemyInRange?
│ └── Action: Shoot()
└── Sequence (Patrol)
├── Action: MoveToWaypoint()
└── Action: Wait(2s)
- Each tick re-evaluates from root.
Running returns control to tree, resumes next tick.
Simple BT Implementation
public enum NodeState { Running, Success, Failure }
public abstract class Node {
public abstract NodeState Evaluate();
}
public class Selector : Node {
List<Node> children;
public override NodeState Evaluate() {
foreach (var child in children) {
var result = child.Evaluate();
if (result != NodeState.Failure) return result;
}
return NodeState.Failure;
}
}
public class Sequence : Node {
List<Node> children;
public override NodeState Evaluate() {
foreach (var child in children) {
var result = child.Evaluate();
if (result != NodeState.Success) return result;
}
return NodeState.Success;
}
}
Blackboard
Shared data store for AI decision-making.
| Variable | Example |
target | Transform of current target |
lastKnownPosition | Vector3 of last sighted player |
alertLevel | Float 0–1 |
patrolIndex | Int, current waypoint |
public class Blackboard {
Dictionary<string, object> data = new();
public void Set<T>(string key, T value) => data[key] = value;
public T Get<T>(string key) => (T)data[key];
public bool Has(string key) => data.ContainsKey(key);
}
Choosing the Right Pattern
| Scenario | Use |
| Simple enemy with 3–5 states | Enum FSM |
| Reusable state logic across enemies | Class-based FSM |
| Animation-heavy character | Animator FSM |
| Complex decisions, many conditions | Behavior Tree |
| Hybrid | BT for decision, FSM for execution |
| GOAP (Goal-Oriented Action Planning) | Dynamic, emergent AI |