본 게임에서 인간 캐릭터들이 몬스터를 공격하거나 도망가는 등 다양한 행동을 한다. 이런 복잡한 행동을 깔끔하게 구현하기 위해 가장 널리 쓰이는 패턴 중 하나가 바로 상태 머신(State Machine) 이다. HumanStateMachine과 관련된 주요 클래스와 상태들을 분석하며, 이 시스템이 어떻게 동작하고 구조적으로 어떤 장점을 가지는지를 살펴보자.
핵심 구성 요소
| 클래스 | 역할 |
| HumanController | 캐릭터의 상태, 속도, 타겟 등을 제어하는 중심 클래스 |
| HumanStateMachine | 현재 상태를 관리하고 상태 전이를 담당 |
| IHumanState | 상태들의 인터페이스 (Enter/Update/Exit 메서드 정의) |
| WalkHumanState, RunHumanState, BattleHumanState | 각각 걷기, 도망, 전투 상태를 구현한 클래스 |
각각의 상태는 Enter(), Update(), Exit() 세 가지 메서드로 구성되어 있고, HumanStateMachine은 이 상태 간의 전이를 조절한다.
캐릭터의 3가지 행동 상태
1. WalkHumanState - "거점으로 향하는 중"
- 상태 진입 시(Enter) :
- 애니메이션을 "걷기"로 설정.
- 스테이지의 목표 지점(거점)으로 이동 경로 설정.
- 상태 갱신 중(Update) :
- TargetMonster가 생기면 즉시 전투 상태로 전환.
if (_human.TargetMonster != null) {
_stateMachine.ChangeState(_human.BattleHumanState);
}
- 상태 종료 시(Exit):
- 이동 경로 초기화.
2. BattleHumanState - "몬스터와 전투 중"
- 상태 진입 시(Enter) :
- "전투" 애니메이션으로 전환.
- TargetMonster의 위치로 이동 설정.
- 회피 우선순위를 최상으로 설정하여 충돌 방지.
- 상태 갱신 중(Update) :
- 타겟 몬스터가 사라지면 WalkHumanState로 전환.
- 일정 시간이 지나고 쿨타임이 지나면 PerformAttack()으로 공격 실행.
if (Time.time >= _lastAttackTime + _human.Cooldown && !_human.isSurprising)
{
PerformAttack();
}
- 공격 메서드(PerformAttack):
- 랜덤한 피로도 값을 몬스터에게 적용.
- 파티클 및 공격 애니메이션 실행.
- 상태 종료 시(Exit) :
- 경로 초기화 및 회피 타입 원복.
3. RunHumanState - "공포에 질려 도망 중"
- 상태 진입 시(Enter) :
- 애니메이션 속도와 이동 속도 증가.
- 스폰된 지점으로 이동.
- 상태 갱신 중(Update) :
- 도착 지점에 다다르면 원래는 풀로 반환 처리 (현재 주석 처리됨).
- 놀란 상태에서 도망가다 풀로 반환하는 것으로 변경됨
private void SetBattleState()
{
if (FearLevel >= MaxFear) // 갱신된 값이 최댓값보다 크면
{
controller.stateMachine.ChangeState(controller.RunHumanState); // 도망 상태로 전환
ReturnHumanToPool(3.0f); // 인간을 풀로 반환
}
}
- 상태 종료 시(Exit) :
- 경로 초기화.
상태 전이의 트리거
상태 전이는 다음과 같은 상황에서 발생한다:
- 몬스터를 감지하면 → 걷기 상태에서 전투 상태로.
- 공포 수치가 최대치에 도달하면 → 전투 상태에서 도망 상태로.
- 타겟 몬스터가 사라지면 → 전투 상태에서 다시 걷기 상태로.
전이는 모두 HumanStateMachine.ChangeState()를 통해 이루어진다:
public void ChangeState(IHumanState newHumanState)
{
_currentHumanState?.Exit();
_currentHumanState = newHumanState;
_currentHumanState?.Enter();
}
HumanController: 상태 머신의 중심 허브
HumanController는 각 상태 객체들을 보유하고 있으며, 상태 머신과 상호작용하는 주요 클래스이다.
WalkHumanState = new WalkHumanState(this);
RunHumanState = new RunHumanState(this);
BattleHumanState = new BattleHumanState(this);
- OnEnable()에서 기본 상태를 걷기로 초기화하고 애니메이션/속도를 세팅.
- Update()에서 현재 상태의 Update()를 지속적으로 호출.
상태 전환의 핵심 조건: 공포 시스템 (Fear)
Human.cs에는 인간의 공포 수치를 관리하는 시스템이 있고, 일정 수치 이상이 되면 도망 상태로 전환된다.
공포 증가 시 Surprise 애니메이션이 실행되며, 타겟 몬스터도 클리어되고 도망 로직이 활성화된다.
private void SetBattleState()
{
if (FearLevel >= MaxFear) // 갱신된 값이 최댓값보다 크면
{
controller.animator.SetBool("IsBattle", false);
controller.ClearTargetMonster();
controller.targetMonsterList.Clear();
controller.stateMachine.ChangeState(controller.RunHumanState); // 도망 상태로 전환
StageManager.Instance.ChangeGold(_coin); // 스테이지 보유 재화 갱신
ReturnHumanToPool(3.0f); // 인간을 풀로 반환
}
}
상태 머신 사용의 이점
- 유지보수 용이: 각 상태가 독립적으로 동작하므로 버그 수정과 확장이 쉬움
- 디버깅 편리: 현재 상태만 확인하면 캐릭터의 AI를 추적 가능
- 유연한 확장: 새로운 상태를 쉽게 추가 가능
이처럼 상태 머신을 사용하여 복잡한 AI 동작을 간단하게 구현하였다. 전투-도망-걷기와 같은 다양한 행동은 각각 독립적인 클래스에서 정의되어 있고, HumanController를 중심으로 통합되어 유기적으로 작동한다.
'프로젝트 기록' 카테고리의 다른 글
| [트러블슈팅] 버튼 이벤트 인덱스 오류 (0) | 2025.10.01 |
|---|---|
| [HighRoWin] 상속과 인터페이스를 활용한 리팩토링 (0) | 2025.05.25 |
| UIManager 설계 (0) | 2025.05.24 |
| PoolManager 설계 (0) | 2025.05.24 |