y의 위치만 Character Controller가 제어하고 XZ의 움직임은 Root Motion에 맡겨야하는데, Root Motion의 동작과 Character Controller가 서로 경쟁을 벌임으로서 약간의 동작 결함이 발생할 수 있다.
OnAnimatorMove 메서드를 활용해서 움직임을 Character Controller가 모두 조작하도록 통합해 볼 것이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float rotationSpeed = 720;
public float jumpSpeed = 5;
public Transform cameraTransform;
private CharacterController characterController;
private Animator animator;
private float ySpeed;
private void Start()
{
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
}
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput);
float inputMagnitude = Mathf.Clamp01(movementDirection.magnitude);
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
inputMagnitude *= 0.5f;
}
animator.SetFloat("Input Magnitude", inputMagnitude, 0.05f, Time.deltaTime);
movementDirection = Quaternion.AngleAxis(cameraTransform.rotation.eulerAngles.y, Vector3.up) * movementDirection;
movementDirection.Normalize();
ySpeed += Physics.gravity.y * Time.deltaTime;
if (movementDirection != Vector3.zero)
{
Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
// 기본 루트모션의 동작을 재정의할 수 있다.
private void OnAnimatorMove()
{
// movementDirection * speed 속도를 animator.deltaPosition으로 대체
// animator.deltaPosition 이는 애니메이션에 의해 결정되는 위치 변경이다.
Vector3 velocity = animator.deltaPosition;
// 프레임마다의 위치 변경은 animator.deltaPosition이 담당하므로 ySpeed에 Time.deltaTime을 곱해준다.
velocity.y = ySpeed * Time.deltaTime;
characterController.Move(velocity);
}
}