[Unity3D] Character Controller와 Root Motion

oy Hong·2024년 5월 2일

Root Motion 적용


스크립트

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);
    }
}

0개의 댓글