이동 상태 Walk와 Run을 추가해주기 위해 PlayerStateMachine에 추가해주자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerStateMachine : StateMachine
{
''' 생략
// States
public PlayerIdleState IdleState { get; }
public PlayerWalkState WalkState { get; }
public PlayerRunState RunState { get; }
''' 생략
public PlayerStateMachine(Player player)
{
this.Player = player;
IdleState = new PlayerIdleState(this);
WalkState = new PlayerWalkState(this);
RunState = new PlayerRunState(this);
MainCameraTransform = Camera.main.transform;
MovementSpeed = player.Data.GroundedData.BaseSpeed;
RotationDamping = player.Data.GroundedData.BaseRotationDamping;
}
}
각각 PlayerWalkState와 PlayerRunState를 선언하고 PlayerStateMachine 생성자에서 new를 통해 각각의 상태를 새로 만들어준다.
이제 PlayerStateMachine에 Walk와 Run 상태가 추가되었으니, PlayerBaseState에서 이동을 위한 키 입력 처리를 해주어야 한다.
protected virtual void AddInputActionsCallbacks()
{
// walk 또는 Run 상태 진입 시의 키 입력을 받아오기 위한 이벤트 구독
PlayerInput input = stateMachine.Player.Input;
input.PlayerActions.Movement.canceled += OnMovementCanceled;
input.PlayerActions.Run.started += OnRunStarted;
}
protected virtual void RemoveInputActionsCallbacks()
{
// 위에서 Walk, Run 상태 진입 시 구독했던 이벤트 해제하기
PlayerInput input = stateMachine.Player.Input;
input.PlayerActions.Movement.canceled -= OnMovementCanceled;
input.PlayerActions.Run.started -= OnRunStarted;
}
pprotected virtual void OnRunStarted(InputAction.CallbackContext context)
{
}
protected virtual void OnMovementCanceled(InputAction.CallbackContext context)
{
}
위에서 정의한 OnMovementCanceled을 override하여 처리해준다.
// Player의 상태가 Ground일 때, 이동 키의 입력을 멈추면 Idle 상태로 진입하게 만든다.
// Air 상태일 때나 Attack 상태일 때는 이동 키의 입력을 멈췄다고 Idle로 변경되면 안되기 때문에 Ground에서 처리해준다.
protected override void OnMovementCanceled(InputAction.CallbackContext context)
{
if (stateMachine.MovementInput == Vector2.zero) return;
stateMachine.ChangeState(stateMachine.IdleState);
base.OnMovementCanceled(context);
}
protected virtual void OnMove()
{
stateMachine.ChangeState(stateMachine.WalkState);
}
주석에 적혀있듯, Player가 Ground 상태일 때만 이동 키의 입력이 멈췄을 때 Idle로 전환되도록 만들어주기 위해 PlayerGroundedState에서 OnMovementCanceled 처리를 해준다.
using UnityEngine.InputSystem;
public class PlayerWalkState : PlayerGroundedState
{
public PlayerWalkState(PlayerStateMachine playerStateMachine) : base(playerStateMachine)
{
}
public override void Enter()
{
stateMachine.MovementSpeedModifier = groundData.WalkSpeedModifier;
base.Enter();
StartAnimation(stateMachine.Player.AnimationData.WalkParameterHash);
}
public override void Exit()
{
base.Exit();
StopAnimation(stateMachine.Player.AnimationData.WalkParameterHash);
}
protected override void OnRunStarted(InputAction.CallbackContext context)
{
base.OnRunStarted(context);
stateMachine.ChangeState(stateMachine.RunState);
}
}
Walk는 플레이어가 땅에 있어야 할 수 있도록 PlayerGroundedState를 상속받아준다. 이후 Enter()에서 플레이어의 이동 속도 MovementSpeedModifier를 플레이어의 데이터에 있는 걸을 때 이동 속도로 변경해준다.
그리고 StartAnimation으로 Walk 값을 true로 변경해주어 애니메이션을 실행하게 된다. 이 때, Parameter는 Ground와 Walk 둘다 true인 상태가 된다.
그리고 걷는 와중에 달리기 키가 입력이 들어오면 RunState으로 변경해주기 위한 OnRunStarted를 구현해준다.
public class PlayerRunState : PlayerGroundedState
{
public PlayerRunState(PlayerStateMachine playerStateMachine) : base(playerStateMachine)
{
}
public override void Enter()
{
// 플레이어 이동 속도를 달리기 속도로 변경하기
stateMachine.MovementSpeedModifier = groundData.RunSpeedModifier;
base.Enter();
StartAnimation(stateMachine.Player.AnimationData.RunParameterHash);
}
public override void Exit()
{
base.Exit();
StopAnimation(stateMachine.Player.AnimationData.RunParameterHash);
}
}
Walk와 마찬가지로 Run 또한 Ground 상태일 때 가능하도록 PlayerGroundedState를 상속받아준다. Enter()에서 플레이어의 이동 속도를 달리기 속도로 변경을 해준다.
플레이어는 Idle 상태에서 Walk, Run으로 상태가 변할 것이기 때문에 이를 위해 코드를 수정해준다.
public override void Update()
{
base.Update();
if(stateMachine.MovementInput != Vector2.zero)
{
// 이동 처리가 들어왔다면 플레이어의 상태를 Idle에서 Walk로 변경해주기
OnMove();
return;
}
}