-
Unity | 유한상태머신(FSM, Finite State Machine)과 상태패턴(State Pattern)다시한번 개발자도전! 2026. 2. 23. 11:25
1. 상태 머신(FSM)이란 무엇인가?
- 유한 상태 머신(Finite State Machine, FSM)은 객체가 가질 수 있는 상태(State)를 한정하고, 특정 조건에 따라 다른 상태로 전이(Transition)하는 설계 방식.
- 플레이어의 AI, 캐릭터 컨트롤러, 복잡한 UI 시스템 등을 관리할 때 필수적으로 쓰임. 핵심은 "객체는 한 번에 오직 하나의 상태만 가질 수 있다"는 점. 예를 들어, 캐릭터가 동시에 '점프'하면서 '사망' 상태일 수는 없는 것과 같음.
2. 왜 상태 머신을 써야 하는가?
단순하게 코드를 짜면 Update() 함수 내부에 수많은 if-else나 switch문이 들어가게 됨. 상태가 3개일 땐 괜찮지만, 10개가 넘어가면 코드가 스파게티처럼 꼬여서 수정하기가 매우 힘들어짐.
- 가독성 향상: 각 상태의 로직이 별도의 클래스나 메서드로 분리됨.
- 유지보수 용이: 새로운 상태(예: 비행, 수영)를 추가할 때 기존 상태의 코드를 건드릴 필요가 없음 (개방-폐쇄 원칙 준수).
- 디버깅 효율: 현재 객체가 어떤 상태인지 명확히 추적할 수 있어 에러 잡기가 쉬움.
3. 상태 패턴(State Pattern)
상태 패턴은 상태 머신을 구현할 때 "상태를 별도의 클래스로 캡슐화"하는 방식.
- SOLID 원칙의 정수: 각 상태가 클래스로 분리되므로 단일 책임 원칙(SRP)을 지키고, 새로운 상태 추가가 쉬워 개방-폐쇄 원칙(OCP)을 만족함.
- 구조: IState 인터페이스를 만들고, IdleState, MoveState 클래스가 이를 상속받아 자기 로직만 실행함.
4. 차이점 비교
구분 상태 머신 (State Machine) 상태 패턴 (State Pattern) 성격 추상적인 모델 / 동작 원리 구체적인 구현 코드 구조 / 디자인 패턴 범위 모든 상태 제어 로직을 통칭함 OOP에서 상태를 객체화하는 특정 기법 유니티 예시 Animator(Mecanim), Enum 기반 제어 C# 클래스로 분리된 State 클래스들 핵심 목표 상태 전환 로직 설계 코드의 유연성과 유지보수성 향상
👩💻상태패턴 구현
1.상태 인터페이스 정의
public interface IState { void Enter(); // 상태에 들어올 때 void Update(); // 매 프레임 실행될 로직 void HandleInput(); // 입력 감지 및 상태 전환 조건 체크 void Exit(); // 상태를 나갈 때 }
2.상태 머신 컨트롤러
public class StateMachine { // 상태들을 저장할 딕셔너리 private Dictionary<System.Type, IState> states = new Dictionary<System.Type, IState>(); public IState CurrentState { get; private set; } // 상태 등록 (한 번만 생성해서 넣어둠) public void AddState(IState state) { states.Add(state.GetType(), state); } public void Initialize<T>() where T : IState { var type = typeof(T); if (states.ContainsKey(type)) { CurrentState = states[type]; CurrentState.Enter(); } } public void ChangeState<T>() where T : IState { CurrentState.Exit(); CurrentState = states[typeof(T)]; CurrentState.Enter(); } }
3.구체적인 상태 구현
public class IdleState : IState //대기상태 { private Player player; public IdleState(Player player) => this.player = player; public void Enter() =>Debug.Log("대기상태"); public void HandleInput() { // 이동 입력이 들어오면 MoveState로 전환 if (player.MoveInput != 0) player.StateMachine.ChangeState<MoveState>(); } public void Update() { / 가만히 있을 때의 로직 / } public void Exit() { } } public class MoveState : IState //이동상태 { private Player player; public MoveState(Player player) => this.player = player; public void Enter() => Debug.Log("이동상태"); public void HandleInput() { // 입력이 끊기면 다시 IdleState로 전환 if (player.MoveInput == 0) player.StateMachine.ChangeState<IdleState>(); } public void Update() => player.Move(); // 실제 이동 처리 public void Exit() { } }
4.실제 플레이어 사용
public class Player : MonoBehaviour { public StateMachine StateMachine { get; private set; } public float MoveInput { get; private set; } void Awake() { StateMachine = new StateMachine(); // 상태 머신에 상태들을 등록만 해줌 StateMachine.AddState(new IdleState(this)); StateMachine.AddState(new MoveState(this)); StateMachine.Initialize<IdleState>(); } void Update() { MoveInput = Input.GetAxisRaw("Horizontal"); StateMachine.CurrentState.HandleInput(); StateMachine.CurrentState.Update(); } public void Move() { transform.Translate(Vector3.right * MoveInput * Time.deltaTime * 5f); } }
실제 작동 모습

'다시한번 개발자도전!' 카테고리의 다른 글
Unity | 델리게이트를(delegate) 활용한 이벤트(Event System) (0) 2026.02.25 Unity | 델리게이트(Delegate) (0) 2026.02.24 Unity | BFS(너비우선 탐색) 와 DFS(깊이우선 탐색) (0) 2026.02.11 Unity | 타일맵(TileMap)과 룰타일(RullTile) (0) 2026.02.02 Unity | 직렬화(SerializeField)란? (0) 2026.01.23