hueam아카이브
상태 기반 애니메이션 & 리플렉션 기반 FSM 본문
리플렉션으로 만드는 FSM
상태 정의
public enum PlayerStateEnum
{
Idle,
Move,
Dash,
Jump,
Fall
}
관리하기 편하게 enum을 통해 상태를 저장해 줬다.
상태 만들기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerState
{
protected PlayerStateMachine _stateMachine;//플레이어 상태머신
protected Player _player;
protected Rigidbody2D _rigidbody;
protected int _animBoolHash;
protected readonly int _yVelocityHash = Animator.StringToHash("y_velocity");
public PlayerState(Player player, PlayerStateMachine stateMachine, string animationBoolName)
{
_player = player;
_stateMachine = stateMachine;
_animBoolHash = Animator.StringToHash(animationBoolName);
_rigidbody = _player.RigidbodyCompo;
}
public virtual void Enter()
{
_player.AnimatorCompo.SetBool(_animBoolHash, true);
}
public virtual void UpdateState()
{
_player.AnimatorCompo.SetFloat(_yVelocityHash, _rigidbody.velocity.y);
}
public virtual void Exit()
{
_player.AnimatorCompo.SetBool(_animBoolHash, false);
}
}
_animBoolHash를 통해 애니메이션을 제어할 수 있게 만들었다.
상태에 들어오면 true로 해주어 애니메이션들 실행 해주고 나가면 false해주어 애니메이션을 나간다.
기본적으로 모든 상태들이 필요한 것들을 만들어 두고 Enter,UpdateState,Exit와 같이 상태마다 다를 걸 생각하여 virtual로 만들어 주었다.
상태 관리
이런식으로 PlayerStateMachine을 만들어 모든 상태들을 관리를 해줬다.
public class PlayerStateMachine
{
public PlayerState CurrentState { get; private set; }
public Dictionary<PlayerStateEnum, PlayerState> StateDIctionary
= new Dictionary<PlayerStateEnum, PlayerState>();
private Player _player;
public void Initialize(PlayerStateEnum startState, Player player)
{
_player = player;
CurrentState = StateDIctionary[startState];
CurrentState.Enter();
}
public void ChangeState(PlayerStateEnum newState)
{
CurrentState.Exit();
CurrentState = StateDIctionary[newState];
CurrentState.Enter();
}
public void AddState(PlayerStateEnum state, PlayerState playerState)
{
StateDIctionary.Add(state, playerState);
}
}
Dictionary를 통해 모든 상태들을 저장하고
CurremtState를 통해 현재 상태를 저장한다.
이 스크립트를 통해 현재상태를 업데이트하며 상태를 바꿀 수 있다.
더욱 자세한 상태
그냥 방식대로 만들게 되면 무한 점프 같은 것이 가능하게 된다.
이를 막기 위해 더욱 더욱 자세한 상태를 만들어 들고 만들 상태를 상속 받으면 된다.
public abstract class PlayerGroundState : PlayerState
{
public PlayerGroundState(Player player, PlayerStateMachine stateMachine, string animationBoolName) : base(player, stateMachine, animationBoolName)
{
}
public override void Enter()
{
base.Enter();
_player.PlayerInput.JumpEvent += HandleJumpInput;
}
public override void Exit()
{
base.Exit();
_player.PlayerInput.JumpEvent -= HandleJumpInput;
}
public override void UpdateState()
{
base.UpdateState();
}
private void HandleJumpInput()
{
if (_player.IsGroundDetected())
{
_stateMachine.ChangeState(PlayerStateEnum.Jump);
}
}
}
이런 식으로 만들어줬다.
리플렉션을 이용해 상태 인스턴스 만들기
public class` Player : MonoBehaviour
{
public PlayerStateMachine StateMachine { get; private set; }
#region 콤포넌트 영역
public Animator AnimatorCompo { get; private set; }
public Rigidbody2D RigidbodyCompo { get; private set; }
public CapsuleCollider2D ColliderCompo { get; private set; }
#endregion
public int FacingDirection { get; private set; } = 1;
protected bool _facingRight = true;
protected virtual void Awake()
{
Transform visualTrm = transform.Find("Visual");
AnimatorCompo = visualTrm.GetComponent<Animator>();
RigidbodyCompo = GetComponent<Rigidbody2D>();
ColliderCompo = GetComponent<CapsuleCollider2D>();
//여기서 스테이트 머신에서 AddState를 실행시킴
StateMachine = new PlayerStateMachine();
foreach (PlayerStateEnum state in Enum.GetValues(typeof(PlayerStateEnum)))
{
string typeName = state.ToString();
Type t = Type.GetType($"Player{typeName}State");
PlayerState newState = Activator.CreateInstance(t, this, StateMachine, typeName) as PlayerState;
StateMachine.AddState(state, newState);
}
StateMachine.Initialize(PlayerStateEnum.Idle, this);
}
}
Enum의 값을 string 으로 변환해서 바꾼 값을 통해 리플렉션을 이용해 상태 스크립트들은 인스턴스로 만들어줘 이를 PlayerStateMachine넣어 관리한다.
상태 기반 애니메이션
위에서 만들 상태들를 기반으로 애니메이션을 실행시키는 거다.
PlayerState 의 셍성자를 통해 상태 이름을 Hash로 바꿔 _animBoolHash에 넣는다.
또한 애니메이션의 Parameter또한 상태 이름에 맞게 만들어줘
상태에 들어갈 때 true로 해주어 그 상태의 맞는 애니메이션을 실행시켜주고 나갈때 false로 해주에 Exit로 나가 Entry로 돌아와 현재 상태에 맞는 애니메이션을 실행시켜준다.
'오래남는 공부 > Unity' 카테고리의 다른 글
InputSystem (0) | 2023.11.25 |
---|