본문 바로가기
공부/유니티

유니티3D 공부(Part 1-2) 플레이어 이동 코드분석, 애니메이션 추가

by 라이티아 2024. 9. 24.

나는 정신이 멍하다

오늘도 즐거운 유니티 공부 시간이다 젠장

 

뭔가 하는건 더럽게 많은데 하는게 없는것 같은 이 느낌

 

일단 계속 하다보면 끝날거라 생각한다

 

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

public class Player_move : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float rotationSpeed = 360f;

    CharacterController characterController;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

        if(direction.sqrMagnitude > 0.01f)
        {
            Vector3 forward = Vector3.Slerp
            (
                transform.forward, direction, rotationSpeed * Time.deltaTime / Vector3.Angle(transform.forward, direction)
            );
            transform.LookAt(transform.position + forward);
        }
        characterController.Move(direction * moveSpeed * Time.deltaTime);
    }
}

대충 이 코드를 씹고뜯고 맛봐야 한다

    public float moveSpeed = 5f;
    public float rotationSpeed = 360f;

대충 시작의 float 변수들은 이동, 회전 속도를 결정한다

        characterController = GetComponent<CharacterController>();

start()에서는 자신 오브젝트의 charactercontroller 컴포넌트를 가져온다

 

그뒤 update()에서 나오는 코드가 이동의 핵심이 된다

 

Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

이 코드에서 핵심은 GetAxis부분인데 키가 입력될시 x, z값이 변화하며 실시간으로 Vector3값이 변화하며 방향이 direction값이 변화하게 된다

 

참고로 Horizontal이 좌우, Vertical이 상하이다.

if(direction.sqrMagnitude > 0.01f)
        {
            Vector3 forward = Vector3.Slerp
            (
                transform.forward, direction, rotationSpeed * Time.deltaTime / Vector3.Angle(transform.forward, direction)
            );
            transform.LookAt(transform.position + forward);
        }

그후, if문을 만나는데 처음보는 부분이 있다

.sqrMagnitude

이건 뭘까? 진짜 모름

 

우리의 cgpt선생님의 대답이다. 벡터값의 제곱값을 return해주는 것 같다.

 

이말인 즉슨, if문의 안쪽의 의미는

플레이어가 이동하려 하는가?(키를 누르면 무조건 벡터의 제곱값은 0을 넘음)

를 의미하는 것 같다

 

            Vector3 forward = Vector3.Slerp
            (
                transform.forward, direction, rotationSpeed * Time.deltaTime / Vector3.Angle(transform.forward, direction)
            );
            transform.LookAt(transform.position + forward);

그뒤, Slerp를 사용하여 자연스러운 방향 전환을 구현한다

 

즉, Slerp는 선형 보간을 통해 부드러운 회전을 만들어낸다

        characterController.Move(direction * moveSpeed * Time.deltaTime);

마지막에 characterController의 move를 사용하여 플레이어 오브젝트를 이동시킨다

 

 

 

이제 여기에 모션을 넣어보자

 

애니메이션 폴더를 만들고 컨트롤러를 만든다

이 애니메이터를 플레이어의 모델에 넣어준다

 

이제 애니메이션을 넣어보자

빈 애니메이터 창이다. 우선 idle 상태부터 만들어 주려 한다

 

필요한 애니메이션을 찾아서 넣어준다

이제 Tshape가 아니라 idle 모션을 취하고 있음을 확인할 수 있다

 

이제 여기에 달리기 모션을 넣어보자

애니메이터에 애니메이션을 넣더라도, 단순히 넣는것 만으로는 적용되지 않는다. 이는 3D든 2D이든 같은 영역이기 때문에, 스크립트를 통해서 애니메이션을 수정해 주어야 한다

 

그렇기에 애니메이터에 파라미터를 넣어서 애니메이션을 변경하여 준다

 

public class Player_move : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float rotationSpeed = 360f;

    Animator animator;

    CharacterController characterController;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

        if(direction.sqrMagnitude > 0.01f)
        {
            Vector3 forward = Vector3.Slerp
            (
                transform.forward, direction, rotationSpeed * Time.deltaTime / Vector3.Angle(transform.forward, direction)
            );
            transform.LookAt(transform.position + forward);
        }
        characterController.Move(direction * moveSpeed * Time.deltaTime);

        animator.SetFloat("Speed", characterController.velocity.magnitude);
    }
}

여기에서 추가된 코드는

Animator animator;
animator = GetComponent<Animator>();
animator.SetFloat("Speed", characterController.velocity.magnitude);

이다

setfloat를 이용하여 캐릭터가 이동하고 있는지 확인하는 것 이다.

 

근데 magnitude키워드는 처음 보는 것 같다

벡터의 길이를 나타내는 속성이라고 한다. charactercontroller.velocity는 vector값이기에 크기를 표현하는 magnitude키워드를 사용할 수 있는 것 같다

 

즉, 플레이어가 이동 상태이면 Speed 파라미터는 무조건 0이 아니게 되는 것 이다.

 

이에 맞추어 애니메이터의 파라미터를 넣어서 애니메이션을 넣어준다

 

 

....근데 책에서 뭔가 이상하게 알려줬는게 있다

 

내가 해석을 잘못한건가?

 

구조가 이렇게 되어 있으면 animator가 player에도 붙어있고 자식 프리팹에도 붙어있는 대참사가 나타나는데, 어쩌라는걸까

 

일단 내가 아는 지식으로는 player에 모델과 애니메이터를 넣는 방식으로 구성하는게 맞아서 이렇게 하는데, 책에는 유니티짱에 넣으라는것 같다...

 

근데 이렇게 하면 굳이 프리팹을 왜???

 

뭐지??

일단 잘 되니까 그러려니 하고 넘어가자

원래 코딩은 이런것....