내일배움캠프 72일차 7/26 TIL + Unit 스크립트와 StateMachine 수정
작업 내용
Unit 스크립트
기존에는 Enemy
나 UserUnit
이 Unit
스크립트를 제대로 상속하지 못했다. 적 유닛과 아군 유닛의 동작이 다르긴 하지만, 공통된 부분이 있을 것 같아 Unit
클래스를 만들어 상속시킬 생각이었다. 그러나 실제로는 겹치는 부분이 매우 적었다. 가장 큰 문제는 이동을 제외하면 공통점이 없다는 점이었다. 아군 유닛은 플레이어 조작에 따라 다양하게 움직이지만 적 유닛은 그냥 라인 따라서 움직이는 것이 전부였다. 따라서 서로 다른 컴포넌트를 묶기도 어려웠다. 결국 Unit
을 만들긴 했지만, UserUnit
에서는 StateMachine
을 수정하면서 상속을 포기했다.
계층적 StateMachine
이제 서로 겹치는 느낌이 강하고, 공격과 이동이 따로 State
가 없어 매우 불편했던 StateMachine
을 손볼 차례다. 계획은 다음과 같다:
- Idle (적이 들어오면
Tracking
으로 전환) - MovingAttack (적이 주변에 없으면
Move
로 전환) - Tracking (적이 멀리 있으면
Move
실행) - Hold
서브 State
- Move (그냥 이동, 나가면 SuperState로 이동)
- Attack (멈추고 공격, 사거리에서 나가면 SuperState로 이동)
Update
에서 적의 위치를 따로 계산해서 반응하게 해줄 수 있지만, 일단 만들어보고 결정할 것이다.
다음은 UserUnitStateMachine
의 코드이다:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserUnitStateMachine
{
#region Private Field
private UserUnitBaseState currentState;
#endregion
#region Public Properties
public UserUnitBaseState CurrentState { get { return currentState; } }
#endregion
#region Public Methods
/// <summary>
/// 평범한 State 바꾸는 함수
/// </summary>
/// <param name="state"></param>
public void ChangeState(UserUnitBaseState state)
{
currentState?.Exit(); // 원래 있던 상태를 꺼냄
currentState = state; // 받아온 상태를 현재 상태에 반환
currentState?.Enter(); // 새로운 것이 들어왔으니 초기화
}
/// <summary>
/// 새로운 SubState로 바꾸는 함수
/// 현재 State를 SuperState로 저장해줌
/// </summary>
/// <param name="state"></param>
public void ChangeToSubState(UserUnitBaseState state)
{
state.SetSuperState(currentState);
currentState?.Exit();
currentState = state;
currentState?.Enter();
}
/// <summary>
/// 현재 State가 가진 SuperState로 바꿔주는 함수
/// </summary>
public void ChangeToSuperState()
{
UserUnitBaseState state = currentState?.SuperState;
currentState?.Exit();
currentState = state;
currentState?.Enter();
}
/// <summary>
/// 매 프레임 업데이트할 State 내용
/// </summary>
public void Update()
{
currentState?.Update(); // 현재 상태 업데이트
}
#endregion
}
Sub
, Super State
로 이동하는 함수가 추가되어 계층적으로 동작한다. 예를 들어, 이동 중 공격 상태이면 기본적으로 SubState
인 Move
로 바꿨다가 적이 등장하면 ChangeToSub
를 호출해서 Attack
상태로 바꾼다. 적이 벗어나면 다시 ChangeToSuperState
를 호출해서 Move
로 바뀌어 하던 이동을 계속 할 수 있다. IdleState
를 루트로 두고 나머지를 그 Sub
로 둘 것이다.
마무리
오늘은 대단한 일은 아니지만, 새로운 구조를 고민하느라 시간이 좀 걸렸다. 계층적 상태 머신(Hierarchical State Machine, HSM)은 이론만 봤을 때는 단순해 보였지만, 실제로 적용하려니 고민이 필요했다. 물론 이 방법이 최선인지 모르겠지만, 내가 생각해낸 방식이고 작동은 의도대로 될 것 같다.