Quick Flow
FSM은 bool을 class로 바꾸는 패턴이 아니라, 현재 mode에서 허용하는 입력·tick·exit 조건을 한곳에 두는 전이 모델입니다. 상태 하나는 OnEnter, Tick, OnExit와 owner가 정한 context만 다루고, 전이는 같은 frame에 재진입하지 않게 한 경로로 요청합니다.
public interface IState
{
void OnEnter();
void Tick();
void OnExit();
}
public sealed class StateMachine
{
IState current;
bool isTransitioning;
public void Change(IState next)
{
if (next == current || isTransitioning) return;
isTransitioning = true;
current?.OnExit();
current = next;
current.OnEnter();
isTransitioning = false;
}
public void Tick() => current?.Tick();
}| 상태로 나눌 기준 | 상태가 아닌 경우 | 확인할 계약 |
|---|---|---|
| 입력·전이·animation rule이 달라짐 | 숫자 tuning만 다름 | enter/exit와 source of truth |
| 동시에 하나만 가능한 main mode | 버프·장비처럼 겹치는 속성 | state 조합 폭발 여부 |
| 시간이 지나거나 event로 다음 mode가 정해짐 | stateless utility algorithm | tick·event의 전이 owner |
| cancel 때 정리할 timer·listener가 있음 | 단순 enum display | exit cleanup과 재진입 |
전이를 한곳으로 모으기
Idle, Run, Jump, Fall처럼 허용 행동이 달라지면 상태를 나눕니다. sprint 속도만 다른 경우까지 state로 만들면 전이 수가 늘고, ArmedPoisonedJumping처럼 서로 독립적인 flag를 state 이름에 넣으면 조합이 폭발합니다. main mode는 FSM에, 장비·buff·cooldown처럼 겹치는 data는 context field 또는 별도 component에 둡니다.
전이는 여러 callback에서 current = next로 직접 바꾸지 않습니다. input, animation event, physics landing, network correction이 같은 frame에 도착할 수 있으므로 priority·queue·ignore 중 하나를 정합니다. OnExit가 event 해제, coroutine cancel, hitbox disable을 맡고 OnEnter가 state-local timer와 animation을 시작한다면, exit가 정확히 한 번 실행되는지가 핵심입니다.
Unity update와 상태 data
Unity에서는 input sampling, physics, presentation이 다른 loop에서 실행될 수 있습니다. state machine의 Tick을 Update에 둘지 FixedUpdate에 둘지는 state의 simulation owner에 맞추고, input을 buffer해 fixed simulation에서 소비할지 명시합니다. OnEnter에서 coroutine이나 async task를 시작했다면 state 종료 후 callback이 current state를 다시 바꾸지 않도록 cancellation token 또는 version을 둡니다.
state instance가 여러 actor에게 공유되면 mutable timer, target, transition reference가 섞입니다. ScriptableObject로 authoring definition을 저장할 수는 있지만, actor별 runtime state는 context나 actor-specific instance가 소유합니다. scene 종료와 actor destroy 시에는 state가 만든 subscription과 task를 정리합니다.
전이 test
각 state에서 허용·무시·defer할 input과, OnEnter -> Tick -> OnExit 순서를 test합니다. 동일 state로의 전이, exit 중 다시 Change를 부르는 경우, destroy 중 cancel, network rollback처럼 경계가 되는 상황을 포함합니다. 상태 수보다 전이 표와 cleanup 경로가 읽히는지가 유지보수 기준입니다.
OnEnter에서 시작한 effect·coroutine·listener를 OnExit에서 멈추지 않으면 다음 state에서도 이전 규칙이 살아 있습니다. FSM 오류는 대개 state class 수가 아니라 전이 재진입과 종료 책임에서 생깁니다.
참고 링크
2 sources