3 분 소요

목표

  1. Player에 무기 장착시키기
  2. Movement에 Animation 적용

일단 Player에 무기를 장착시켜보자
Player Prefab을 보면 jointItemR 이라는 오브젝트가 있다.
보통 모델링 하는 사람들이 이러한 이름으로 아이템을 장착시키는 위치를 저장하는 오브젝트를 만들어둔다.
이곳에 무기 Prefab을 넣어주면 무기가 장착된다.

image

나중에 코드로 무기를 장착시킬 위치를 저장해서 필요한 아이템들을 교체하면서 착용시켜 줄 것이다.
일단은 Animation 조정을 위해 임시로 착용해준다.

일단 Idle 상태의 애니메이션을 추가해보자

구매한 애니메이션 에셋에 Animator를 복사해주고 Player에 적용시켜준다.

image

Animator를 켜보면 다음과 같이 Idle 상태로 기본 애니메이션이 Transition 되어 있다.

image

이제 Move에 관한 애니메이션을 적용시켜 줄 것이다. 나는 BlendTree를 이용하여 상하좌우 이동, Sprint 적용하는 애니메이션을 혼합해서 사용할 것이다.

BlendTree Type의 종류

  1. 2D Simple Directional :
    • “앞으로 걷기”, “뒤로 걷기”, “왼쪽으로 걷기”, “오른쪽으로 걷기” 또는 “위로 조준”, “아래로 조준”, “왼쪽 조준”과 같이 모션이 서로 다른 방향을 나타낼 때 가장 적합합니다. ”, 그리고 “올바른 조준”. 선택적으로 위치(0, 0)에서 “유휴” 또는 “똑바로 조준”과 같은 단일 동작을 포함할 수 있습니다. 단순 방향성 유형에서는 “앞으로 걷기” 및 “앞으로 달리기”와 같이 동일한 방향으로 여러 모션이 있어서는 안 됩니다.
  2. 2D Freeform Directional :
    • 이 블렌드 유형은 모션이 서로 다른 방향을 나타내는 경우에도 사용되지만 “앞으로 걷기” 및 “앞으로 달리기”와 같이 동일한 방향으로 여러 모션을 가질 수 있습니다. Freeform Directional 유형에서 모션 세트는 항상 “idle”과 같은 위치(0, 0)의 단일 모션을 포함해야 합니다.
  3. 2D Freeform Cartesian :
    • 모션이 다른 방향을 나타내지 않을 때 가장 적합합니다. Freeform Cartesian을 사용하면 X 매개변수와 Y 매개변수가 각속도 및 선형 속도와 같은 다양한 개념을 나타낼 수 있습니다. 예를 들어 “회전 없이 앞으로 걷기”, “회전 없이 앞으로 뛰기”, “앞으로 걷기 우회전”, “앞으로 뛰기 우회전” 등과 같은 동작이 있습니다.

image

나는 2D Freeform Directional을 선택했다. 왜냐하면 Idle 상태에서 Left or Right 방향으로 이동할 때, 턴하는 동작을 넣음으로써 조금더 부드러운 동작을 구현하기 위함이다. Simple을 선택한다면 같은 방향에서 여러 모션이 있으면 안되기 때문에 제외시켰다.

기본적으로 8방향에 Jogging하는 모션을 적용시켰다.

Parameter로는 Float형으로 X, Z를 저장한 변수를 만들었다. GetAxis로 받은 키보드 WASD 값에 따른 X, Z 값을 받아 애니메이션을 적용시키기 위함이다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private float moveSpeed;
    [SerializeField]
    private float jumpForce;
    [SerializeField]
    private float walkSpeed;
    [SerializeField]
    private float sprintSpeed;

    private CharacterController characterController;
    private Vector3 moveDir;
    private KeyCode sprintKey;
    private KeyCode jumpKey;
    private Animator animator; // 애니메이터 추가

    public enum MovementState
    {
        Idle,
        Walking,
        Sprint,
        Jumping
    }
    public MovementState state;

    private void Start()
    {
        jumpForce = 4.0f;
        walkSpeed = 5.0f;
        sprintSpeed = 10.0f;
        moveSpeed = walkSpeed;
        characterController = GetComponent<CharacterController>();
        sprintKey = KeyCode.LeftShift;
        jumpKey = KeyCode.Space;
        state = MovementState.Idle;
        animator = GetComponent<Animator>(); // 애니메이터 가져옴
    }

    private void Update()
    {
        StateHandler();

        if (characterController.isGrounded)
        {
            float x = Input.GetAxis("Horizontal");
            float z = Input.GetAxis("Vertical");
            moveDir = new Vector3(x, 0, z);

            if (Input.GetKey(jumpKey))
                moveDir.y = jumpForce;
        }

        animator.SetFloat("X", moveDir.x); // 애니메이터 파라미터 X값 적용 
        animator.SetFloat("Z", moveDir.z); // 애니메이터 파라미터 Z값 적용
        moveDir.y += Physics.gravity.y * Time.deltaTime;
        characterController.Move(moveDir * moveSpeed * Time.deltaTime);
    }

    private void StateHandler()
    {
        if (characterController.isGrounded && Input.GetKey(sprintKey))
        {
            state = MovementState.Sprint;
            moveSpeed = sprintSpeed;
        }
        else if (characterController.isGrounded)
        {
            state = MovementState.Walking;
            animator.SetBool("IsWalking", true); // 애니메이터 파라미터 Walking 상태 적용
            moveSpeed = walkSpeed;
        }
        else
        {
            state = MovementState.Jumping;
        }
    }
}

1

이동 애니메이션 적용 사진이다.

다음은 점프 애니메이션을 적용해보자

image

애니메이터에 점프의 시작을 알리는 트리거 파라미터와 점프의 시작과 종료를 알리는 bool타입의 파라미터를 정의했다. bool 타입은 점프가 종료되는 시점에 JumpEnd 애니메이션을 실행하기 위함이다. 코드는 다음과 같이 수정했다.

    private void Update()
    {

        if (characterController.isGrounded)
        {
            animator.SetBool("IsJumping", false); // 땅에 닿으면 점프 종료
            float x = Input.GetAxis("Horizontal");
            float z = Input.GetAxis("Vertical");
            moveDir = new Vector3(x, 0, z);
            state = MovementState.Walking;
            animator.SetBool("IsWalking", true);
            animator.SetBool("IsSprint", false);
            moveSpeed = walkSpeed;
            if (Input.GetKey(sprintKey) && moveDir != Vector3.zero)
            {
                state = MovementState.Sprint;
                moveSpeed = sprintSpeed;
                animator.SetBool("IsSprint", true);
                animator.SetBool("IsWalking", false);
            }
            if (Input.GetKey(jumpKey))
            {
                moveDir.y = jumpForce;
                state = MovementState.Jumping;
                animator.SetBool("IsJumping", true); // 점프 중인 것 확인 
                animator.SetBool("IsWalking", false); // 걷는중이 아니임
                animator.SetTrigger("DoJump"); // 점프 트리거 실행
            }
        }
        animator.SetFloat("X", moveDir.x);
        animator.SetFloat("Z", moveDir.z);
        moveDir.y += Physics.gravity.y * Time.deltaTime;
        characterController.Move(moveDir * moveSpeed * Time.deltaTime);
    }

점프 애니메이션은 이것이 전부다 다음은 Sprint 대쉬 애니메이션을 구현해보자 내가 생각하는 Sprint는 앞 방향키를 눌렀을 때 빠른속도로 달리는 것이다.

image

이전에 Walking을 구현한 BlendTree에 Z가 2인 경우에 빠르게 달리는 모션을 실행하도록 애니메이션을 하나 추가해준다.

    private void Update()
    {

        if (characterController.isGrounded)
        {
            animator.SetBool("IsJumping", false);
            float x = Input.GetAxis("Horizontal");
            float z = Input.GetAxis("Vertical");
            moveDir = new Vector3(x, 0, z);
            animator.SetBool("IsWalking", true);
            
            if (Input.GetKey(sprintKey) && moveDir.z > 0) // 앞 방향만 허용
            {
                state = MovementState.Sprint;
                animator.SetFloat("X", moveDir.x);
                animator.SetFloat("Z", moveDir.z * 2); // Z에 2를 곱해서 적용
                moveSpeed = sprintSpeed;
            }
            else
            {
                state = MovementState.Walking;
                animator.SetFloat("X", moveDir.x);
                animator.SetFloat("Z", moveDir.z);
                moveSpeed = walkSpeed;
            }

            if (Input.GetKey(jumpKey))
            {
                moveDir.y = jumpForce;
                state = MovementState.Jumping;
                animator.SetBool("IsJumping", true);
                animator.SetBool("IsWalking", false);
                animator.SetTrigger("DoJump");
            }
        }
        moveDir.y += Physics.gravity.y * Time.deltaTime;
        characterController.Move(moveDir * moveSpeed * Time.deltaTime);
    }

Sprint 조건으로 moveDir.z > 0를 추가함으로 앞 방향키를 눌렀을 때만 허용하도록 한다. 그리고 BlendTree의 조건에 맞게 Z 축이 2의 값을 가질 수 있도록 x2를 해준다.

2

여기까지 움직임 애니메이션 적용을 마친다.
다음은 카메라를 조정하여 플레이어가 바라보는 방향으로 카메라가 조정되도록 구현해보자.

업데이트: