[Unity] State Pattern을 활용해 AI FSM 구조화
게임에서 AI가 다양한 행동을 수행하도록 만들기 위해 가장 많이 사용하는 구조 중 하나가 FSM(Finite State Machine)이다. 예를 들어, 적 캐릭터가 '대기 → 추적 → 공격 → 도망'과 같은 여러 상태를 가지며 상황에 따라 행동이 전환되는 로직은 대부분 FSM 기반으로 설계된다. 이를 객체지향적으로 구현하기 위한 가장 대표적인 방식이 바로 State Pattern(상태 패턴)이다.
FSM(Finite State Machine)이란
FSM은 유한한 개수의 상태(State)를 정의하고, 그 중 하나의 상태만을 가지며, 조건에 따라 다른 상태로 전이(Transition)되는 구조다. AI 시스템에 이 구조를 적용하면, 각 상태별 행동을 분리하고 전이 조건을 정의함으로써 복잡한 행동 로직을 명확하고 유지보수 가능하게 만든다.
State Pattern이란
State Pattern은 객체의 내부 상태에 따라 행동을 바꾸는 디자인 패턴이다. 유니티에서는 이 패턴을 활용해 각 상태를 클래스로 분리하고, 인터페이스 또는 추상 클래스를 통해 통합된 형태로 관리할 수 있다. 이렇게 하면 상태 간의 전환 로직과 상태별 동작을 깔끔하게 분리할 수 있다.
기본 구조 예시
1. 상태 인터페이스 정의
public interface IState
{
void Enter();
void Execute();
void Exit();
}
2. 상태 클래스 구현
public class IdleState : IState
{
private EnemyAI enemy;
public IdleState(EnemyAI enemy)
{
this.enemy = enemy;
}
public void Enter()
{
Debug.Log("Idle 상태 진입");
}
public void Execute()
{
if (enemy.CanSeePlayer())
{
enemy.ChangeState(new ChaseState(enemy));
}
}
public void Exit()
{
Debug.Log("Idle 상태 종료");
}
}
3. 상태를 전환하는 메인 FSM 컨트롤러
public class EnemyAI : MonoBehaviour
{
private IState currentState;
void Start()
{
ChangeState(new IdleState(this));
}
void Update()
{
currentState?.Execute();
}
public void ChangeState(IState newState)
{
currentState?.Exit();
currentState = newState;
currentState.Enter();
}
public bool CanSeePlayer()
{
// 간단한 시야 판정 예시
return Vector3.Distance(transform.position, Player.Instance.transform.position) < 10f;
}
}
장점
- 상태별 로직이 분리되어 유지보수가 쉽다.
각 상태를 별도 클래스로 구현하면, 복잡한 조건문 없이도 AI 동작을 관리할 수 있다. - 확장성이 뛰어나다.
새로운 상태를 추가하거나 기존 상태를 수정할 때 다른 코드에 영향을 주지 않는다. - 디버깅이 명확하다.
현재 상태, 상태 전이, 상태별 행동이 명확히 구분되므로 테스트와 로그 분석이 쉬워진다. - 테스트 가능성이 높아진다.
상태 객체를 개별적으로 테스트할 수 있어 유닛 테스트 적용이 가능하다.
주의 사항
- 클래스 수가 많아질 수 있다. 상태가 많아질수록 클래스도 증가하므로 관리가 필요하다.
- 간단한 AI에는 오히려 과할 수 있다. 단순히 "대기/공격" 수준의 로직이라면 enum + switch로 처리하는 것이 더 효율적일 수 있다.
- 상태 전이 조건을 중복 없이 관리해야 한다. 중복된 전이 조건이 있으면 AI가 예기치 않게 행동할 수 있다.
마무리
State Pattern을 활용한 FSM 구조는 유니티에서 AI를 체계적으로 구성하는 데 매우 적합하다. 상태를 클래스로 분리하고, 전이 로직과 행동을 구분하면 코드가 깔끔해지고 협업에도 유리하다. 특히 상태 수가 많거나, 상태 간 전환이 복잡한 적/보스/동료 NPC 등의 AI를 개발할 때 큰 효과를 발휘한다.
유니티의 MonoBehaviour 구조에 자연스럽게 녹여낼 수 있는 패턴이므로, 프로젝트에 맞춰 적절히 구조화하면 강력한 AI 시스템을 설계할 수 있다.