내일배움캠프 42일차 6/14 TIL + Unity공부
유한 상태 기계 (Finite State Machine, FSM) 정리
개요
유한 상태 기계(Finite State Machine, FSM)는 프로그래밍 및 시스템 설계에서 사용되는 모델로, 특정 개체가 가질 수 있는 상태와 이러한 상태 간의 전환을 정의합니다. FSM은 주로 게임 개발, 특히 AI와 게임 오브젝트의 행동을 관리하는 데 자주 사용됩니다.
주요 개념
- 상태 (State)
- 개체가 특정 시간에 있을 수 있는 하나의 조건 또는 상황을 의미합니다.
- 예: 플레이어 캐릭터의 상태는 “Idle”, “Running”, “Jumping” 등이 될 수 있습니다.
- 전환 (Transition)
- 하나의 상태에서 다른 상태로의 이동을 의미합니다.
- 특정 조건이 충족될 때 전환이 발생합니다.
- 예: 플레이어가 “Idle” 상태에서 “Running” 상태로 전환하려면 “MoveForward” 입력이 필요합니다.
- 이벤트 (Event)
- 상태 전환을 트리거하는 동작 또는 조건입니다.
- 예: 키 입력, 충돌 감지 등.
- 액션 (Action)
- 상태 전환 시 수행되는 동작입니다.
- 예: 애니메이션 변경, 소리 재생 등.
FSM 구현 예시
-
플레이어 캐릭터의 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; } }
-
적 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의 장점
- 명확한 구조:
- 상태와 전환이 명확히 정의되어 코드의 가독성이 높아집니다.
- 유연성:
- 새로운 상태나 전환을 쉽게 추가할 수 있습니다.
- 재사용성:
- FSM 로직을 다른 개체나 시스템에서 재사용할 수 있습니다.
FSM의 단점
- 복잡성 증가:
- 상태와 전환이 많아질수록 FSM의 복잡성이 증가합니다.
- 상태 폭발:
- 모든 상태와 전환을 정의해야 하므로, 상태가 많아지면 관리가 어려워질 수 있습니다.
FSM은 게임 개발에서 캐릭터의 행동, AI, 게임 상태 관리 등에 매우 유용한 도구입니다. 이를 잘 활용하면 보다 체계적이고 유지보수 가능한 코드를 작성할 수 있습니다.