2 minute read

유한 상태 기계 (Finite State Machine, FSM) 정리

개요

유한 상태 기계(Finite State Machine, FSM)는 프로그래밍 및 시스템 설계에서 사용되는 모델로, 특정 개체가 가질 수 있는 상태와 이러한 상태 간의 전환을 정의합니다. FSM은 주로 게임 개발, 특히 AI와 게임 오브젝트의 행동을 관리하는 데 자주 사용됩니다.

주요 개념

  1. 상태 (State)
    • 개체가 특정 시간에 있을 수 있는 하나의 조건 또는 상황을 의미합니다.
    • 예: 플레이어 캐릭터의 상태는 “Idle”, “Running”, “Jumping” 등이 될 수 있습니다.
  2. 전환 (Transition)
    • 하나의 상태에서 다른 상태로의 이동을 의미합니다.
    • 특정 조건이 충족될 때 전환이 발생합니다.
    • 예: 플레이어가 “Idle” 상태에서 “Running” 상태로 전환하려면 “MoveForward” 입력이 필요합니다.
  3. 이벤트 (Event)
    • 상태 전환을 트리거하는 동작 또는 조건입니다.
    • 예: 키 입력, 충돌 감지 등.
  4. 액션 (Action)
    • 상태 전환 시 수행되는 동작입니다.
    • 예: 애니메이션 변경, 소리 재생 등.

FSM 구현 예시

  1. 플레이어 캐릭터의 FSM (간단한 예)

     public enum PlayerState
     {
         Idle,
         Running,
         Jumping
     }
    
     public class PlayerController : MonoBehaviour
     {
         private PlayerState currentState;
    
         void Start()
         {
             currentState = PlayerState.Idle;
         }
    
         void Update()
         {
             switch (currentState)
             {
                 case PlayerState.Idle:
                     if (Input.GetKeyDown(KeyCode.Space))
                     {
                         TransitionToState(PlayerState.Jumping);
                     }
                     else if (Input.GetKey(KeyCode.W))
                     {
                         TransitionToState(PlayerState.Running);
                     }
                     break;
    
                 case PlayerState.Running:
                     if (!Input.GetKey(KeyCode.W))
                     {
                         TransitionToState(PlayerState.Idle);
                     }
                     else if (Input.GetKeyDown(KeyCode.Space))
                     {
                         TransitionToState(PlayerState.Jumping);
                     }
                     break;
    
                 case PlayerState.Jumping:
                     if (IsGrounded())
                     {
                         TransitionToState(PlayerState.Idle);
                     }
                     break;
             }
         }
    
         void TransitionToState(PlayerState newState)
         {
             // 상태 전환 시 필요한 동작 수행
             currentState = newState;
             // 상태 전환 시 액션 수행 예시
             switch (newState)
             {
                 case PlayerState.Idle:
                     // Idle 상태로 전환 시 필요한 동작
                     break;
                 case PlayerState.Running:
                     // Running 상태로 전환 시 필요한 동작
                     break;
                 case PlayerState.Jumping:
                     // Jumping 상태로 전환 시 필요한 동작
                     break;
             }
         }
    
         bool IsGrounded()
         {
             // 바닥에 있는지 확인하는 로직
             return true;
         }
     }
    
  2. 적 AI의 FSM (고급 예)

     public enum EnemyState
     {
         Patrol,
         Chase,
         Attack
     }
    
     public class EnemyAI : MonoBehaviour
     {
         private EnemyState currentState;
         private Transform player;
    
         void Start()
         {
             currentState = EnemyState.Patrol;
             player = GameObject.FindGameObjectWithTag("Player").transform;
         }
    
         void Update()
         {
             switch (currentState)
             {
                 case EnemyState.Patrol:
                     Patrol();
                     if (CanSeePlayer())
                     {
                         TransitionToState(EnemyState.Chase);
                     }
                     break;
    
                 case EnemyState.Chase:
                     Chase();
                     if (CanAttackPlayer())
                     {
                         TransitionToState(EnemyState.Attack);
                     }
                     else if (!CanSeePlayer())
                     {
                         TransitionToState(EnemyState.Patrol);
                     }
                     break;
    
                 case EnemyState.Attack:
                     Attack();
                     if (!CanAttackPlayer())
                     {
                         TransitionToState(EnemyState.Chase);
                     }
                     break;
             }
         }
    
         void TransitionToState(EnemyState newState)
         {
             currentState = newState;
             switch (newState)
             {
                 case EnemyState.Patrol:
                     // Patrol 상태로 전환 시 필요한 동작
                     break;
                 case EnemyState.Chase:
                     // Chase 상태로 전환 시 필요한 동작
                     break;
                 case EnemyState.Attack:
                     // Attack 상태로 전환 시 필요한 동작
                     break;
             }
         }
    
         void Patrol()
         {
             // 순찰 로직
         }
    
         void Chase()
         {
             // 추격 로직
         }
    
         void Attack()
         {
             // 공격 로직
         }
    
         bool CanSeePlayer()
         {
             // 플레이어를 볼 수 있는지 확인하는 로직
             return Vector3.Distance(transform.position, player.position) < 10f;
         }
    
         bool CanAttackPlayer()
         {
             // 플레이어를 공격할 수 있는지 확인하는 로직
             return Vector3.Distance(transform.position, player.position) < 2f;
         }
     }
    

FSM의 장점

  1. 명확한 구조:
    • 상태와 전환이 명확히 정의되어 코드의 가독성이 높아집니다.
  2. 유연성:
    • 새로운 상태나 전환을 쉽게 추가할 수 있습니다.
  3. 재사용성:
    • FSM 로직을 다른 개체나 시스템에서 재사용할 수 있습니다.

FSM의 단점

  1. 복잡성 증가:
    • 상태와 전환이 많아질수록 FSM의 복잡성이 증가합니다.
  2. 상태 폭발:
    • 모든 상태와 전환을 정의해야 하므로, 상태가 많아지면 관리가 어려워질 수 있습니다.

FSM은 게임 개발에서 캐릭터의 행동, AI, 게임 상태 관리 등에 매우 유용한 도구입니다. 이를 잘 활용하면 보다 체계적이고 유지보수 가능한 코드를 작성할 수 있습니다.