숏컷 코드
Idle -> Run -> Jump -> Fall -> Land문법과 예시
if/bool 더미는 상태가 늘어날수록 전이 규칙을 숨긴다
초기에는 isJumping, isAttacking, isGrounded 같은 bool 몇 개로 캐릭터 상태를 관리할 수 있습니다. 문제는 상태 수가 늘수록 전이 조건이 코드 곳곳에 흩어집니다. "isGrounded && !isJumping && !isAttacking이면 이동 가능" 같은 조건이 여러 메서드에 나타나면, 새 상태를 추가할 때 조건을 놓치기 쉽고 "왜 이 상태에서 저 입력이 먹히지"를 추적하기 어려워집니다. FSM은 이 복잡성을 명시적인 상태 객체 또는 전이 테이블로 끌어내 가시화하는 것이 핵심입니다.
// if 더미 방식: 조건이 흩어짐
if (isGrounded && !isJumping && !isStunned)
StartRun();
// FSM 방식: 상태별 허용 입력이 명확
class IdleState : IState {
void OnInput(InputEvent e) {
if (e == Jump) fsm.ChangeState(jumpState);
if (e == Move) fsm.ChangeState(runState);
}
}상태 경계가 다르면 상태를 나눠야 한다
Jump와 Fall을 구분하는 이유는 이름이 예뻐서가 아닙니다. 점프 중에는 추가 점프를 막고, 낙하 중에는 피격 시 다른 반응을 하며, 착지(Land) 상태에는 짧은 recovery 시간이 있습니다. 허용 입력, 애니메이션, 피격 반응, 물리 처리가 실제로 다르다면 다른 상태입니다. 반대로 Sprint가 단순히 Run의 속도만 다르고 모든 규칙이 동일하다면 별도 상태가 아니라 속도 파라미터로 처리하는 것이 더 적합합니다. 상태 분리 기준은 "허용 행동과 금지 행동의 집합이 다른가"입니다.
// Jump 상태: 허용/금지 명확
Jump {
허용: 방향 전환, 공격
금지: 점프 재입력, 구르기
전이: 속도 음수 && 상승 끝 -> Fall
}
Fall {
허용: 방향 전환
금지: 공격, 점프
전이: 지면 감지 -> Land
}enter/exit 처리 누락이 FSM 버그의 가장 흔한 원인이다
상태 전이 시 이전 상태의 OnExit와 새 상태의 OnEnter를 호출하는 것이 표준 패턴입니다. 이 훅이 없으면 이전 상태에서 시작한 애니메이션이 계속 재생되거나, 새 상태에서 필요한 초기화가 빠져 첫 프레임에 잘못된 동작이 나타납니다. 특히 전이가 동시에 여러 조건에 의해 트리거될 수 있는 경우, 같은 프레임에 OnExit가 여러 번 호출되지 않도록 "전이 중" 플래그를 관리하거나 큐를 써야 합니다.
동시에 겹쳐 존재하는 속성은 FSM보다 별도 데이터로 관리한다
무기 장착 여부, 버프 존재 여부, 스텔스 상태처럼 다른 상태와 독립적으로 동시에 겹쳐 존재할 수 있는 정보는 FSM 상태로 만들면 복잡해집니다. ArmedIdleState, UnarmedIdleState, BuffedArmedIdleState처럼 조합이 폭발합니다. 이런 경우는 태그, 별도 bool 필드, 레이어드 FSM, 또는 별도 컴포넌트로 관리하는 것이 자연스럽습니다. FSM은 "지금 이 객체의 주된 mode"를 관리하는 도구이며, 모든 flag를 대체하는 만능 도구가 아닙니다.
상태 구조를 나눌 때 핵심
| 상황 | 적합한 선택 |
|---|---|
| 허용/금지 행동이 상태마다 명확히 다를 때 | FSM 상태 분리 |
| 속도나 파라미터만 다른 경우 | 같은 상태 + 파라미터 |
| 동시에 겹치는 독립 속성 | 별도 bool/태그/컴포넌트 |
| 상태 수가 많고 전이가 복잡할 때 | 계층형 FSM(HFSM) 또는 Behavior Tree 고려 |
| 전이 버그 디버깅 | OnEnter/OnExit 호출 순서 및 중복 호출 확인 |
| 단순 메뉴 단계처럼 상태 수가 적고 전이가 고정일 때 | enum + 중앙 switch도 충분할 수 있음 |
특이 케이스와 주의할 점
흔한 실패는 겹쳐 존재하는 속성까지 전부 FSM 상태 이름으로 밀어 넣어 ArmedPoisonedJumping 같은 조합 폭발을 만드는
것입니다. 주된 mode만 FSM으로 관리하고, 독립 속성은 태그나 별도 컴포넌트로 빼세요. 전이 버그의 대부분은 상태 수보다
OnEnter/OnExit 누락과 전이 경계 모호함에서 나옵니다.
참고 링크
1 sources