상세 컨텐츠

본문 제목

유니티 캐릭터 컨트롤러 이동, 회전, 경사 오르기

유니티/기능

by MJ_119 2024. 7. 24. 00:23

본문

출처 : https://www.youtube.com/watch?v=5GZD4AeZRcA&t=1331s

 

@캐릭터 이동, 마우스 화면 제어, 점프

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

public class CharacterControllerMove : MonoBehaviour
{
    public float walkSpeed = 5f;
    public float runSpeed = 10f;
    public float mouseSensitivity = 2f;
    private CharacterController characterController;

    public GameObject skateboard; // 스케이트보드

    // 애니메이터
    Animator animator;

    // 점프 코드
    public float jumpPower = 8f;
    float gravity = -9.81f;
    Vector3 velocity;


    // 카메라 회전
    float currentCameraRotationX = 0;
    public Camera cam;

    // 지면 체크
    bool isGrounded;
    public Transform groundCheck;
    public float groundDistance = 0.5f;
    public LayerMask groundMask;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
        skateboard.SetActive(false);
    }

    void Update()
    {
        Move();
        CharacterRotation();
        CameraRotation();
    }

    public void CharacterRotation()
    {
        // 좌우 캐릭터 회전
        float yRotation = Input.GetAxisRaw("Mouse X") * mouseSensitivity;

        // 기존의 회전에 새로운 회전을 더하여 적용
        transform.Rotate(0, yRotation, 0);
    }
    public void CameraRotation()
    {
        // 상하 카메라 회전
        float xRotation = Input.GetAxisRaw("Mouse Y");
        float cameraRotationX = xRotation * mouseSensitivity;

        currentCameraRotationX -= cameraRotationX;

        currentCameraRotationX = Mathf.Clamp(currentCameraRotationX, -45, 45);
        cam.transform.localEulerAngles = new Vector3(currentCameraRotationX, 0, 0);
    }
    public void Move()
    {
        // 지면 체크( 땅 밟고있는지 체크 )
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (velocity.y < 0 && isGrounded)
        {
            // 지면에 있을 때는 y 속도를 작은 음수로 설정 (지면에 붙여주는 역할)
            velocity.y = -2f;

            animator.SetBool("JumpOn", false);
        }

        float moveX = Input.GetAxisRaw("Horizontal");
        float moveZ = Input.GetAxisRaw("Vertical");

        Vector3 move = transform.right * moveX + transform.forward * moveZ; // 1,0,0 * X    0,0,1 * Z

        float moveSpeed = walkSpeed;

        animator.SetFloat("x", moveX);
        animator.SetFloat("y", moveZ);

        if (Input.GetKey(KeyCode.LeftShift))
        {
            moveSpeed = runSpeed;
        }

        print("is Grounded : " + isGrounded);

        move.Normalize();
        characterController.Move(move * moveSpeed * Time.deltaTime);


        // 점프 입력 처리
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = jumpPower;
            animator.SetTrigger("Jump");
            animator.SetBool("JumpOn", true);
            
        }

        // 중력 적용
        velocity.y += gravity * Time.deltaTime;

        // 중력 및 점프 속도 적용
        characterController.Move(velocity * Time.deltaTime);

        //print("G velocity.y : " + velocity.y);

    }
}

 

 

 

 

 

캐릭터 이동 및 블렌드 애니메이션 적용

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    private CharacterController controller;
    private Animator animator;
    

    // 이동 관련 코드
    float input_x;
    float input_z;
    public float moveSpeed = 5f; // 캐릭터 이동 속도
    bool runCheck; // 달리기 체크 

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

    void Update()
    {
        PlayerMovement();
    }

    private void PlayerMovement()
    {
        input_x = Input.GetAxisRaw("Horizontal");
        input_z = Input.GetAxisRaw("Vertical");

        Vector3 move = transform.right * input_x + transform.forward * input_z;

        runCheck = false;

        if (Input.GetKey(KeyCode.LeftShift))
        {
            runCheck = true;
        }

        move.y = 0f;

        move.Normalize();
        move = move * (runCheck ? 1 : 0.5f);
        controller.Move(move * moveSpeed * Time.deltaTime);

        animator.SetFloat("Move", move.magnitude);
        print(move);
    }
}

 

 

 

이동 + 점프 + 점프 애니메이션 추가

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    private CharacterController controller;
    private Animator animator;

    // 이동 코드
    float input_x;
    float input_z;
    public float moveSpeed = 5f; // 캐릭터 이동 속도
    bool runCheck; // 달리기 체크 

    // 점프 코드
    public float jumpPower = 10f;
    float gravity = -9.81f;
    Vector3 velocity;

    // 지면 체크
    bool isGrounded;
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;

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

    void Update()
    {
        PlayerMovement();
        PlayerTurn();
    }

    private void PlayerTurn()
    {
        //transform.Rotate();
    }

    private void PlayerMovement()
    {
        // 지면 체크( 땅 밟고있는지 체크 )
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (velocity.y < 0 && isGrounded)
        {
            // 지면에 있을 때는 y 속도를 작은 음수로 설정 (지면에 붙여주는 역할)
            velocity.y = -2f;

            animator.SetBool("JumpOn", false);
            
        }

        input_x = Input.GetAxisRaw("Horizontal");
        input_z = Input.GetAxisRaw("Vertical");

        Vector3 move = transform.right * input_x + transform.forward * input_z;

        // 달리기 체크
        runCheck = Input.GetKey(KeyCode.LeftShift);

        move.Normalize();

        // 왼쪽 쉬프트 누르면 달리기, 안누르면 걷기모션 재생하기 위한 코드
        move = move * (runCheck ? 1 : 0.5f); 
       
        // 애니메이터 Move에 값 전달
        animator.SetFloat("Move", move.magnitude); 

        // 이동 구현
        controller.Move(move * moveSpeed * Time.deltaTime); 

        
        print(move); // move값 확인


        // 점프 입력 처리
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = jumpPower;
            animator.SetTrigger("Jump");
            animator.SetBool("JumpOn", true);
        }

        // 중력 적용
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

 

 

지면체크, 이동, 점프의 올바른 코드 순서

  • 지면 체크: 먼저 캐릭터가 지면에 있는지 확인합니다.
  • 이동 처리: 플레이어의 입력을 받아 이동 방향과 속도를 결정합니다.
  • 점프 처리: 플레이어가 점프 버튼을 눌렀을 때 점프를 수행합니다.
  • 중력 적용: 중력을 적용하여 캐릭터가 자연스럽게 낙하하도록 합니다.
  • 캐릭터 이동: 계산된 이동 벡터와 중력 벡터를 사용하여 캐릭터를 이동시킵니다.

 

 

 

 

 

 

이동, 누른 방향으로 즉각적인 회전 구현 ( 부드러운 움직임 X )

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEditor.Experimental.GraphView;
using UnityEditor.Rendering;
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    private CharacterController controller;
    private Animator animator;

    // 이동 코드
    float input_x;
    float input_z;
    public float moveSpeed = 5f; // 캐릭터 이동 속도
    bool runCheck; // 달리기 체크 

    // 점프 코드
    public float jumpPower = 10f;
    float gravity = -9.81f;
    Vector3 velocity;

    // 지면 체크
    bool isGrounded;
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask groundMask;

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

    void Update()
    {
        PlayerMovement();
    }


    private void PlayerMovement()
    {
        // 지면 체크( 땅 밟고있는지 체크 )
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (velocity.y < 0 && isGrounded)
        {
            // 지면에 있을 때는 y 속도를 작은 음수로 설정 (지면에 붙여주는 역할)
            velocity.y = -2f;

            animator.SetBool("JumpOn", false);
        }

		// 키 입력 받는 부분(A,D,W,S)
        input_x = Input.GetAxisRaw("Horizontal");
        input_z = Input.GetAxisRaw("Vertical");

        // 입력에 따른 이동 방향 설정
        Vector3 move = new Vector3(input_x, 0, input_z).normalized;
        
        // 캐릭터 회전
        if (move != Vector3.zero) // 움직임이 있을때에만 회전하도록 조건문 설정
        {
            // 입력 방향으로 캐릭터 회전
            Quaternion toRotation = Quaternion.LookRotation(move, Vector3.up);
            transform.rotation = toRotation;
        }


        // 달리기 체크
        runCheck = Input.GetKey(KeyCode.LeftShift);

        // 왼쪽 쉬프트 누르면 달리기, 안누르면 걷기모션 재생하기 위한 코드
        move = move * (runCheck ? 1 : 0.5f);

        // 이동 구현
        controller.Move(move * moveSpeed * Time.deltaTime);

        // 애니메이터 Move에 값 전달
        animator.SetFloat("Move", move.magnitude);
        
        // 점프 입력 처리
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = jumpPower;
            animator.SetTrigger("Jump");
            animator.SetBool("JumpOn", true);
        }

        // 중력 적용
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

 

 

@ 이동 및 회전 부분 코드만 작성한것. ( 8방향으로 딱딱하게 움직임 )  대각선 부드러운 움직임 X

void Update()
{
    // 입력값을 받아 이동 방향 설정
    float inputX = Input.GetAxisRaw("Horizontal");
    float inputZ = Input.GetAxisRaw("Vertical");
    Vector3 move = new Vector3(inputX, 0, inputZ).normalized;

    // 이동 방향이 있는 경우에만 회전
    if (move != Vector3.zero)
    {
        // 입력 방향으로 캐릭터 회전
        Quaternion toRotation = Quaternion.LookRotation(move, Vector3.up);
        transform.rotation = toRotation;
    }

    // 캐릭터 이동
    controller.Move(move * moveSpeed * Time.deltaTime);
}

 

@ 이동 및 회전을 부드럽게 하기 ( 모든 방향을 부드럽게 회전 )

Quaternion.Slerp(currentRotation, targetRotation, t) 사용

Slerp() : 현재 위치에서 ( currentRotation ) 바라볼 위치로 ( targetRotation ) 얼마만큼 빠르게 ( t ) 회전하는지 .

float rotationSpeed = 15f;

void Update()
{
    // 입력값을 받아 이동 방향 설정
    float inputX = Input.GetAxisRaw("Horizontal");
    float inputZ = Input.GetAxisRaw("Vertical");
    Vector3 move = new Vector3(inputX, 0, inputZ).normalized;

    // 이동 방향이 있는 경우에만 회전
    if (move != Vector3.zero)
    {
        // 입력 방향으로 캐릭터 회전
        Quaternion toRotation = Quaternion.LookRotation(move, Vector3.up);
        transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
    }

    // 캐릭터 이동
    controller.Move(move * moveSpeed * Time.deltaTime);
}

 

toRotation 값 : 쿼터니언 (0.00000, 0.70711, 0.00000, 0.70711)

 

 

 

 

 

@ 로컬 좌표계 이동 방법.

input_x = Input.GetAxisRaw("Horizontal");
input_z = Input.GetAxisRaw("Vertical");

// 입력에 따른 상하 좌우 이동 설정
Vector3 move = new Vector3(input_x, 0, input_z).normalized;
move = transform.TransformDirection(move);

// 캐릭터 회전
if (move != Vector3.zero) // 움직임이 있을때에만 회전하도록 조건문 설정
{
    // 입력 방향으로 캐릭터 회전
    Quaternion toRotation = Quaternion.LookRotation(move, Vector3.up);
    // 부드러운 움직임
    transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
// 이동 구현
controller.Move(move * moveSpeed * Time.deltaTime);

 

@ 기본적인 상하좌우 움직임, 마우스로 화면 상하, 캐릭터 좌우 이동

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

public class CharacterControllerMove : MonoBehaviour
{
    public float speed = 5f;
    public float mouseSensitivity = 2f;
    private CharacterController characterController;

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

    void Update()
    {
        Move();
        CharacterRotation();
    }

    public void CharacterRotation()
    {
        // 좌우 캐릭터 회전
        float yRotation = Input.GetAxisRaw("Mouse X") * mouseSensitivity;

        // 기존의 회전에 새로운 회전을 더하여 적용
        transform.Rotate(0, yRotation, 0);
    }

    public void Move()
    {
        float moveX = Input.GetAxisRaw("Horizontal");
        float moveZ = Input.GetAxisRaw("Vertical");

        Vector3 move = transform.right * moveX + transform.forward * moveZ;

        characterController.Move(move * speed * Time.deltaTime);
    }
}

 

 

 

 

 

관련글 더보기