1 minute read

작업 내용

Unit 스크립트

기존에는 EnemyUserUnitUnit 스크립트를 제대로 상속하지 못했다. 적 유닛과 아군 유닛의 동작이 다르긴 하지만, 공통된 부분이 있을 것 같아 Unit 클래스를 만들어 상속시킬 생각이었다. 그러나 실제로는 겹치는 부분이 매우 적었다. 가장 큰 문제는 이동을 제외하면 공통점이 없다는 점이었다. 아군 유닛은 플레이어 조작에 따라 다양하게 움직이지만 적 유닛은 그냥 라인 따라서 움직이는 것이 전부였다. 따라서 서로 다른 컴포넌트를 묶기도 어려웠다. 결국 Unit을 만들긴 했지만, UserUnit에서는 StateMachine을 수정하면서 상속을 포기했다.

계층적 StateMachine

이제 서로 겹치는 느낌이 강하고, 공격과 이동이 따로 State가 없어 매우 불편했던 StateMachine을 손볼 차례다. 계획은 다음과 같다:

  1. Idle (적이 들어오면 Tracking으로 전환)
  2. MovingAttack (적이 주변에 없으면 Move로 전환)
  3. Tracking (적이 멀리 있으면 Move 실행)
  4. 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로 이동하는 함수가 추가되어 계층적으로 동작한다. 예를 들어, 이동 중 공격 상태이면 기본적으로 SubStateMove로 바꿨다가 적이 등장하면 ChangeToSub를 호출해서 Attack 상태로 바꾼다. 적이 벗어나면 다시 ChangeToSuperState를 호출해서 Move로 바뀌어 하던 이동을 계속 할 수 있다. IdleState를 루트로 두고 나머지를 그 Sub로 둘 것이다.

마무리

오늘은 대단한 일은 아니지만, 새로운 구조를 고민하느라 시간이 좀 걸렸다. 계층적 상태 머신(Hierarchical State Machine, HSM)은 이론만 봤을 때는 단순해 보였지만, 실제로 적용하려니 고민이 필요했다. 물론 이 방법이 최선인지 모르겠지만, 내가 생각해낸 방식이고 작동은 의도대로 될 것 같다.