이 글을 읽기 전 FSM이 무엇인지 알고 오면 좋습니다.
BaseGameEntity.cs
...
[HideInInspector]
public Animator Animator;
public virtual void Setup()
{
Animator = GetComponent<Animator>();
}
public abstract void Updated();
...
모든 씬에 존재하는 모든 Entity들이 상속받는 기반 클래스 BaseGameEntity 스크립트 입니다.
이 클래스는 엔티티들이 기본적으로 가져야 할 초기화(Setup)와 업데이트(Updated) 기능을 제공하며, 상속받는 클래스에서 구체적인 동작을 정의할 수 있도록 설계되었습니다.
전체 코드
https://github.com/HerFS/Unity-RPG/tree/main/Assets/_Scripts/FSM
StateMachine.cs
public class StateMachine<T> where T : class
{
private T _ownerEntity;
private StateOfPlay<T> _currentState;
public StateOfPlay<T> CurrentState => _currentState;
public void Setup(T owner, StateOfPlay<T> entryState)
{
_ownerEntity = owner;
_currentState = null;
ChangeState(entryState);
}
public void Execute()
{
if (_currentState != null)
{
_currentState.Execute(_ownerEntity);
}
}
public void ChangeState(StateOfPlay<T> newState)
{
if (newState == null)
{
return;
}
if (_currentState != null)
{
_currentState.Exit(_ownerEntity);
}
_currentState = newState;
_currentState.Enter(_ownerEntity);
}
}
StateMachine 클래스는 여러 Entity들의 상태를 관리하고 제어하기 위해 *제네릭 방식으로 구현된 상태 기계(State Machine)입니다.
StateOfPlay.cs
public abstract class StateOfPlay<T> where T : class
{
public abstract void Enter(T entity);
public abstract void Execute(T entity);
public abstract void Exit(T entity);
}
PlayerEntity.cs
...
public static StateOfPlay<PlayerEntity>[] States { get; private set; }
public static StateMachine<PlayerEntity> StateMachine { get; private set; }
public bool IsHausted { get; private set; }
private void Awake()
{
Setup();
}
private void Update()
{
...
Updated();
}
public override void Setup()
{
base.Setup();
States = new StateOfPlay<PlayerEntity>[6];
StateMachine = new StateMachine<PlayerEntity>();
States[(int)EnumTypes.PlayerState.Idle] = new PlayerOwnedStates.Idle();
States[(int)EnumTypes.PlayerState.Talk] = new PlayerOwnedStates.Talk();
States[(int)EnumTypes.PlayerState.Walk] = new PlayerOwnedStates.Walk();
States[(int)EnumTypes.PlayerState.Run] = new PlayerOwnedStates.Run();
States[(int)EnumTypes.PlayerState.Attack] = new PlayerOwnedStates.Attack();
States[(int)EnumTypes.PlayerState.Die] = new PlayerOwnedStates.Die();
StateMachine.Setup(this, States[(int)EnumTypes.PlayerState.Idle]);
}
public override void Updated()
{
StateMachine.Execute();
}
public static void ChangeState(EnumTypes.PlayerState newState)
{
StateMachine.ChangeState(States[(int)newState]);
}
...
전체 코드
https://github.com/HerFS/Unity-RPG/blob/main/Assets/_Scripts/FSM/Player/PlayerEntity.cs
플레이어 Entity의 상태를 관리하는 시스템으로 State의 종류는 "Idle", "Talk", "Walk", "Run", "Attack", "Die" 6종류로
각 스탯마다 정해진 작업들을 수행합니다.
상태들을 표현하기 위해 열거형 형태로 정의 했습니다.
Enum 형태들을 사용하는 이유는 상태를 명확하게 표현할 수 있어 코드의 가독성을 높여 상태를 직관적으로 이해할 수 있습니다. 이렇게 Enum 형태들로 정의한 이유는 "https://herfs.tistory.com/10" 을 확인하시면 됩니다.
마지막으로 Player Entity 상태 종류에 대해 보여드리겠습니다.
PlayerOwnedStates.cs
namespace PlayerOwnedStates
{
public class Idle : StateOfPlay<PlayerEntity>
{
public override void Enter(PlayerEntity entity)
{
entity.Animator.CrossFade(Globals.AnimationName.Idle, 0.2f);
}
public override void Execute(PlayerEntity entity)
{
if (Input.GetMouseButtonDown((int)EnumTypes.MouseButton.Left) &&
!Cursor.visible &&
GameManager.Instance.IsGameStart)
{
PlayerEntity.ChangeState(EnumTypes.PlayerState.Attack);
}
if (InputManager.Instance.MoveVector.magnitude != 0f)
{
PlayerEntity.ChangeState(EnumTypes.PlayerState.Walk);
}
}
public override void Exit(PlayerEntity entity)
{
}
}
public class Walk : StateOfPlay<PlayerEntity>
{
public override void Enter(PlayerEntity entity)
{
entity.Animator.CrossFade(Globals.AnimationName.Walk, 0f);
}
public override void Execute(PlayerEntity entity)
{
if (Input.GetMouseButtonDown((int)EnumTypes.MouseButton.Left) &&
!Cursor.visible &&
GameManager.Instance.IsGameStart)
{
PlayerEntity.ChangeState(EnumTypes.PlayerState.Attack);
}
if (InputManager.Instance.MoveVector.magnitude == 0f)
{
PlayerEntity.ChangeState(EnumTypes.PlayerState.Idle);
}
else if (!(entity.IsHausted) && InputManager.Instance.IsRun)
{
PlayerEntity.ChangeState(EnumTypes.PlayerState.Run);
}
}
public override void Exit(PlayerEntity entity)
{
}
}
...
}
전체 코드
https://github.com/HerFS/Unity-RPG/blob/main/Assets/_Scripts/FSM/Player/PlayerOwnedStates.cs
Enter 메소드에서는 CrossFade 메소드를 사용해 애니메이션 상태를 변경합니다.
Execute 메소드에서는 각자 상태에 맞는 행동을 처리합니다.
'Unity > 3D Project' 카테고리의 다른 글
3D RPG - 데이터 저장(Json) (0) | 2024.07.03 |
---|---|
3D RPG - 플레이어의 움직임(Player Controller) (0) | 2024.07.01 |
3D RPG - 플레이어 입력 (Input System) (0) | 2024.07.01 |
3D RPG - 플레이어 정보(Player Status) (0) | 2024.07.01 |
3D RPG - 프로젝트 시작 (0) | 2024.07.01 |