FSM( Finite State Machine )이란 한정된 상태들과 그 상태 간의 전이를 정의하여 게임 오브젝트의 동작을 제어하는 패턴이다. 게임에서 오브젝트가 여러 상태를 가지고 있고, 각 상태에서는 특정 동작을 수행하거나 다른 상태로 전환할 수 있는 구조이다. 유니티에서는 Animator Controller를 생각하면 이해하기 쉽다. 한 State에 머무르며 행동을 하다 특정 조건을 만족하면 다른 State로 Transition을 하는 시스템이다.
플레이어가 있다고 가정을 해보자. 플레이어의 상태를 3가지로 구분할 수 있다.
- Idle : 아무것도 하지 않는 상태
- Move : 움직이는 상태
- Stun : 경직에 걸려 움직이지 못하는 상태

유니티에서 간단하게 FSM을 구현해보자.
using System;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public enum EMyState
{
IdleMyState,
MoveMyState,
StunMyState
}
public interface IMyState
{
void EnterState();
void ExcuteState();
void ExitState();
}
public abstract class VMyState : MonoBehaviour,IMyState
{
[NonSerialized]public StateMachine OwnerStateMachine;
// HSFM 이용 할 시
public StateMachine HSFM_StateMachine;
public abstract void EnterState();
public abstract void ExcuteState();
public abstract void ExitState();
}
public class StateMachine : MonoBehaviour
{
[SerializeField] private EMyState defaultState;
private IMyState _currentMyState;
private Dictionary<EMyState, IMyState> _states = new();
private void ChangeState_Internal(IMyState newMyState)
{
if (_currentMyState != null)
{
_currentMyState.ExitState();
}
_currentMyState = newMyState;
_currentMyState.EnterState();
}
public void ChangeState(EMyState state)
{
ChangeState_Internal(_states[state]);
}
// Start is called before the first frame update
void Start()
{
// 1번 이거는 성능이 직접 컴포넌트 가져오는 방식 대비 비싸다.
VMyState[] stateArray = GetComponents<VMyState>();
foreach (var state in stateArray)
{
state.OwnerStateMachine = this;
EMyState outEnum;
if (EMyState.TryParse(state.GetType().ToString(), out outEnum))
{
_states.Add(outEnum, state);
}
}
// 2번 아레의 방식이 좀 더 비용적으로 저렴하다.
// _states.Add(EMyState.IdleMyState, GetComponent<IdleMyState>());
// _states.Add(EMyState.MoveMyState, GetComponent<MoveMyState>());
// _states.Add(EMyState.StunMyState, GetComponent<StunMyState>());
// DefaultState
ChangeState(EMyState.IdleMyState);
}
// Update is called once per frame
void Update()
{
if (_currentMyState != null)
{
_currentMyState.ExcuteState();
}
}
}
StateMachine 스크립트이다.
using UnityEngine;
public class IdleMyState : VMyState
{
public override void EnterState()
{
}
public override void ExcuteState()
{
if (Input.GetKey(KeyCode.W))
{
OwnerStateMachine.ChangeState(EMyState.MoveMyState);
}
else if (Input.GetKey(KeyCode.F))
{
OwnerStateMachine.ChangeState(EMyState.StunMyState);
}
}
public override void ExitState()
{
}
}
using UnityEngine;
public class MoveMyState : VMyState
{
public float speed;
public override void EnterState()
{
}
public override void ExcuteState()
{
if (Input.GetKey(KeyCode.W))
{
OwnerStateMachine.transform.position += OwnerStateMachine.transform.forward * (Time.deltaTime * speed);
}
else if (Input.GetKey(KeyCode.S))
{
OwnerStateMachine.transform.position -= OwnerStateMachine.transform.forward * (Time.deltaTime * speed);
}
else if (Input.GetKey(KeyCode.F))
{
OwnerStateMachine.ChangeState(EMyState.StunMyState);
}
else
{
OwnerStateMachine.ChangeState(EMyState.IdleMyState);
}
}
public override void ExitState()
{
}
}
using System.Collections;
using UnityEngine;
public class StunMyState : VMyState
{
IEnumerator Stun()
{
yield return new WaitForSeconds(3.0f);
OwnerStateMachine.ChangeState(EMyState.IdleMyState);
}
public override void EnterState()
{
OwnerStateMachine.StartCoroutine(Stun());
}
public override void ExcuteState()
{
}
public override void ExitState()
{
}
}
순서대로 Idle,Move,Stun 상태 스크립트이다.


Idle 상태에서 W키를 누르면 Move상태로 전이되어 움직이고 F키를 누르면 Stun상태로 전이 되는것을 확인할 수 있다.
FSM은 게임 개발에서 NPC나 AI를 구현하는 데 유용한 패턴이다. 구조가 단순하고 직관적이어서 초기 단계에서는 유용하지만 상태의 수가 많아지고 행동 패턴이 복잡해질수록 관리와 유지보수가 어려워질 수 있다. 따라서 사용 전에 프로젝트의 요구사항과 AI의 복잡성을 신중하게 분석하고 사용해야 한다.
'개인 공부 > 디자인패턴' 카테고리의 다른 글
| 유니티 메멘토 (1) | 2024.07.19 |
|---|---|
| 유니티 옵저버 (1) | 2024.07.19 |
| 디자인패턴 커맨드 & 유니티 커스텀 에디터 (1) | 2024.07.16 |
| 디자인패턴 책임 연쇄 패턴 (Chain of Responsibility) (0) | 2024.07.16 |
| 디자인패턴 컴포지트 (0) | 2024.07.15 |