이번 3D 방치형 프로젝트에 몬스터와 플레이어 AI에 상태 패턴을 적용하여 FSM(Finite State Machine)을 간단하게 구현해보았다.
NavMeshAgent, Animator 등 컴포넌트 관리stateMachineUnitStatSO, unitStat) 및 체력 관리public class UnitBase : MonoBehaviour
{
public StateMachine stateMachine { get; private set; }
public IdleState IdleState { get; private set; }
public ChasingState ChasingState { get; private set; }
public AttackState AttackState { get; private set; }
protected virtual void Awake()
{
stateMachine = new StateMachine();
IdleState = new IdleState(this);
ChasingState = new ChasingState(this);
AttackState = new AttackState(this);
}
}
public interface IState
{
void Enter();
void Update();
void Exit();
}
타겟이 감지되면 ChasingState로 전이
IdleState
public void Update()
{
if (unit.Target != null && unit.IsTargetInRange(unit.unitStat.chaseRange))
{
unit.stateMachine.ChangeState(unit.ChasingState);
}
}
ChasingState
AttackState로 전이public void Update()
{
unit.Agent.SetDestination(unit.Target.position);
if (unit.IsTargetInRange(unit.unitStat.attackRange))
{
unit.stateMachine.ChangeState(unit.AttackState);
}
}
AttackState
IdleState로 전이public void Update()
{
if (Time.time - lastAttackTime >= attackCooldown)
{
unit.Attack();
lastAttackTime = Time.time;
}
}
상태 간 전이를 처리(Enter, Exit)하며 현재 상태의 Update()를 매 프레임 호출합니다.
public class StateMachine
{
private IState currentState;
public void ChangeState(IState newState)
{
currentState?.Exit();
currentState = newState;
currentState.Enter();
}
public void Update()
{
currentState?.Update();
}
}
UnitBase 클래스로 묶어서 처리UnitBase에 공통 로직을 묶고, FSM은 상태 전이만 관리하도록 책임 분리가 잘 되어 있어 확장에 용이AttackState에선 쿨타임 계산을 통해 프레임마다 공격하지 않도록 조절 가능