앉기 및 슬라이딩
이제 파쿠르 동작을 구현해 보자.
첫 번째로 슬라이딩을 구현하려 하는데 이는 앉기 키와 동일하게 사용할 예정이라 앉기를 먼저 구현하고 달리면서 앉기 키를 눌렀을 때 슬라이딩이 되도록 구현할 것이다.
앉기
Control키를 눌러 캐릭터가 앉을 수 있도록 만들어 보자.
우선 입력부터 처리하자.

누르고 있을 때만 상태를 변경해야 하기 때문에 PassThrough로 설정하였다.
public void OnCrouch(InputValue value)
{
crouch = value.isPressed;
}
crouch가 참일 때 상태를 변경해 보자.
if (blackBoard.parkourInputController.crouch && _currentParkourState != ParkourState.Crouch)
{
ChangeParkourState(ParkourState.Crouch);
}
웅크린 상태에 들어가면 애니메이션을 변경해 주자.
public override void OnEnter()
{
_playerBlackBoard.animator.SetTrigger(AnimationHash.Crouch);
}

왼쪽 컨트롤키를 누르고 있을 때 앉기 애니메이션을 실행하려 하는데 현재 상태로는 press는 탐지가 가능한데 release를 탐지할 수 없다.
따라서 InputValue가 아니라 InputAction.CallbackContext를 사용하도록 이벤트 방식을 변경해야 할 것 같다.

C# 이벤트로 처리하도록 옵션을 변경하면 다음과 같이 제어할 수 있다.
public void OnCrouch(InputAction.CallbackContext context)
{
if(context.started) crouch = true;
else if(context.canceled) crouch = false;
}
이제 컨트롤러 쪽에서 crouch에 따라 상태를 변경해 주면 된다.
if (blackBoard.parkourInputController.crouch)
{
if (_currentParkourState != ParkourState.Crouch)
{
ChangeParkourState(ParkourState.Crouch);
}
}
else
{
if (_currentParkourState != ParkourState.OnGround)
{
ChangeParkourState(ParkourState.OnGround);
}
}
그리고 애니메이터에서 crouch조건에 따라 애님 스테이트를 변경해주면 끝이다.


이제 Crouch상태에서 이동할 수 있도록 만들어 보자.
Crouch상태에서 OnGround와 마찬가지로 입력에 따라 이동시키면 된다.
var moveInput = _playerBlackBoard.parkourInputController.moveInput;
if (moveInput != Vector2.zero)
{
_targetRotation = Mathf.Atan2(moveInput.x, moveInput.y) * Mathf.Rad2Deg + _playerBlackBoard.mainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(_parkourCharacterController.transform.eulerAngles.y, _targetRotation, ref _rotationVelocity, _playerBlackBoard.playerMovementData.rotationSmoothTime);
_parkourCharacterController.transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
_targetSpeed = 1f;
}
else
{
_targetSpeed = 0f;
}
if (!_playerBlackBoard.animator.IsUnityNull())
{
float alpha = Time.deltaTime * _playerBlackBoard.playerMovementData.speedChangeRate;
alpha *= _playerBlackBoard.parkourInputController.moveInput != Vector2.zero ? 1 : _playerBlackBoard.playerMovementData.decelerateRate;
_animSpeed = Mathf.Lerp(_animSpeed, _targetSpeed, alpha);
_playerBlackBoard.animator.SetFloat(AnimationHash.SpeedAnimID, _animSpeed);
}

슬라이딩
이동 중에 앉기 키를 누르면 슬라이딩하도록 변경해 보자.
그러기 위해서는 이동하면서 바로 슬라이딩 애니메이션이 나올 수도 있고 충분한 속도가 없으면 바로 앉아서 걸어가도록 만드는 것이 자연스러울 것이다.
그렇다면 애니메이터의 상태를 변경해야 할 것 같다.
현재는 LocoMotion에서 앉기 키가 입력되면 바로 보간 애니메이션이 실행 후 앉은 상태가 되며 빠져나올 때도 동일하다.
하지만 이동 중에 앉기 키가 입력되면 바로 앉아서 걸어가야 하므로 보간 애니메이션이 실행되면 제자리에 멈췄다가 앉게 된다.
따라서 이를 나눠 다른 분기로 분리해 줘야 한다.
Speed가 0.1 이상일 때는 바로 앉아서 이동하도록 그렇지 않고 앉기 키만 눌렸다면 보간 애니메이션 이후 앉은 상태가 되도록 하면 된다.

- Idle → Stand_ToCrouch: Crouch입력이 주어졌을 때
- Stand_ToCrouch → Crouch: 조건 없이 보간 애니메이션이 종료되면
- Crouch → Crouch_ToStand: Crouch입력이 해제되었을 때
- Move → Crouch: Crouch입력이 켜지면서 Speed가 0.1 이상일 때
- Crouch → Move: Crouch입력이 해제되면서 Speed가 0.1이상일 때

이제 속도가 임계치 이상이면 Crouch가 아닌 다른 스테이트로 보내면 된다.
즉, Move에서 Crouch로 전환되는 경우가 2가지가 된다.
- Crouch입력이 주어지고 속도가 임계치 이상일 경우: 슬라이딩
- Crouch입력이 주어지고 속도가 임계치 이하일 경우: CrouchMove


슬라이딩 이후에 만약 Coruch입력이 유지 중이라면 앉은 상태를 유지하여 이동하거나 Idle상태가 되며 Crouch입력이 해제되면 일어나 있는 상태로 변경해 주면 된다.

슬라이딩 속도 개선
슬라이딩할 때 속도가 애니메이션 속도에 맞춰져 있기 때문에 살짝 느린감이 있어서 속도에 계수를 추가해 속도감을 올려주고 싶다.
public override void HandleAnimation()
{
Vector3 deltaPosition = _playerBlackBoard.animator.deltaPosition;
if (!_playerBlackBoard.animator.IsUnityNull())
{
var currentState = _playerBlackBoard.animator.GetCurrentAnimatorStateInfo(0);
if (currentState.IsName("SprintCrouch"))
{
deltaPosition *= Mathf.Max(1, _playerBlackBoard.animator.GetFloat(AnimationHash.SpeedAnimID));
}
}
_playerBlackBoard.characterController.Move(deltaPosition);
}
Crouch상태에서 현재 SprintCrouch가 실행 중이라면 Speed 계수를 곱해 속도를 보정해 주었다.
Speed값은 Sprint키를 누르는 여부에 따라 값이 달라지기 때문에 슬라이딩 이후 Sprint키를 해제할 수 있으므로 최솟값을 1로 설정해 느려지는 것을 방지했다.

