[Unity] 3D CharacterController (이동)

남이섬·2023년 3월 24일
0

CharacterController 컴포넌트

Mesh Renderer

이동 Script

// Movement3D
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement3D : MonoBehaviour
{
    [SerializeField]
    private float moveSpeed = 5.0f; // 이동 속도
    private Vector3 moveDirection; // 이동 방향

    private CharacterController characterController;

    private void Awake()
    {
        characterController = GetComponent<characterController>();
    }
    
    private void Update()
    {
        characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
    }

    public void MoveTo(Vector3 direction)
    {
        moveDirection = direction;
    }
}

// PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Movement3D movement3D;

    private void Awake()
    {
        movement3D = GetComponent<Movement3D>();
    }

    private void Update()
    {
        // x, z 방향 이동
        float x = Input.GetAxisRaw("Horizontal"); // 방향키 좌/우 움직임
        float z = Input.GetAxisRaw("Vertical"); // 방향키 위/아래 움직임

        movement3D.MoveTo(new Vector3(x, 0, z));
    } 
}

CharacterController 컴포넌트는 충돌처리는 가능하지만 중력은 적용되지 않는다
중력은 스크립트를 통하여 입력을 해야한다

중력

// Movement3D
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement3D : MonoBehaviour
{
    [SerializeField]
    private float moveSpeed = 5.0f; // 이동 속도
    private Vector3 moveDirection; // 이동 방향

    private float gravity = -9.81f; // 중력 계수

    private CharacterController characterController;

    private void Awake()
    {
        characterController = GetComponent<CharacterController>();
    }
    
    private void Update()
    {
        if(characterController.isGrounded == false)
        {
            moveDirection.y += gravity * Time.deltaTime;
        }
        characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
    }

    public void MoveTo(Vector3 direction)
    {
        // moveDirection = direction;
        moveDirection = new Vector3(direction.x, moveDirection.y, direction.z);
    }
}

CharacterController.isGround
발 위치의 충돌을 체크해 충돌이 되면 true, 충돌이 되지 않으면 false값을 나타내는 변수

점프

if (characterController.isGrounded == false)
{
	moveDirection.y += gravity * Time.deltaTime;
}
// Movement3D
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement3D : MonoBehaviour
{
    [SerializeField]
    private float moveSpeed = 5.0f; // 이동 속도
    [SerializeField]
    private float jumpForce = 3.0f; // 뛰는 힘
    private float gravity = -9.81f; // 중력 계수
    private Vector3 moveDirection; // 이동 방향

    private CharacterController characterController;

    private void Awake()
    {
        characterController = GetComponent<CharacterController>();
    }
    
    private void Update()
    {
        if (characterController.isGrounded == false)
        {
            moveDirection.y += gravity * Time.deltaTime;
        }
        characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
    }

    public void MoveTo(Vector3 direction)
    {
        // moveDirection = direction;
        moveDirection = new Vector3(direction.x, moveDirection.y, direction.z);
    }

    public void JumpTo()
    {
        if (characterController.isGrounded == true)
        {
            moveDirection.y = jumpForce;
        }
    }
}
// PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Movement3D movement3D;
    private KeyCode jumpKeyCode = KeyCode.Space;

    private void Awake()
    {
        movement3D = GetComponent<Movement3D>();
    }

    private void Update()
    {
        // x, z 방향 이동
        float x = Input.GetAxisRaw("Horizontal"); // 방향키 좌/우 움직임
        float z = Input.GetAxisRaw("Vertical"); // 방향키 위/아래 움직임

        movement3D.MoveTo(new Vector3(x, 0, z));

        // 점프키(스페이스)를 눌러 y축 방향으로 뛰어오르기
        if (Input.GetKeyDown(jumpKeyCode))
        {
            movement3D.JumpTo();
        }
    } 
}

경사면이동과 계단이동

경사면이동

  • Slope Limit
    경사 한계 각도, 위와 같이 45도로 되어있으면 45도까지의 경사만 올라갈 수 있다

계단이동

  • Step Offset
    서로 인접한 두 계단 사이의 높이가 Step offset 이하일 때 계단을 올라 갈 수 있다

1인칭 카메라 제어

카메라 오브젝트가 플레이어를 쫓아 다니도록 플레이어 오브젝트의 자식으로 설정을 한다

카메라 회전

// Movement3D
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement3D : MonoBehaviour
{
    [SerializeField]
    private float moveSpeed = 5.0f; // 이동 속도
    [SerializeField]
    private float jumpForce = 3.0f; // 뛰는 힘
    private float gravity = -9.81f; // 중력 계수
    private Vector3 moveDirection; // 이동 방향

    private CharacterController characterController;
    [SerializeField]
    private Transform cameraTransform; // 카메라 Transform 컴포넌트

    private void Awake()
    {
        characterController = GetComponent<CharacterController>();
    }
    
    private void Update()
    {
        if (characterController.isGrounded == false)
        {
            moveDirection.y += gravity * Time.deltaTime;
        }
        characterController.Move(moveDirection * moveSpeed * Time.deltaTime);
    }

    public void MoveTo(Vector3 direction)
    {
        // 카메라가 보고있는 전방방향 기준으로 이동할 수 있도록 
        Vector3 moveDdis = cameraTransform.rotation * direction;
        //                           회전 값을 방향 정보에 곱해 준다
        moveDirection = new Vector3(moveDdis.x, moveDirection.y, moveDdis.z);
    }

    public void JumpTo()
    {
        if (characterController.isGrounded == true)
        {
            moveDirection.y = jumpForce;
        }
    }
}

CameraController

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

public class CameraController : MonoBehaviour
{
    private float rotateSpeedX = 3;
    private float rotateSpeedY = 5;
    private float limitMinX = -80;
    private float limitMaxX = 50;
    private float eulerAngleX;
    private float eulerAngleY;

    public void RotateTo(float mouseX, float mouseY)
    {
        // 마우스를 좌/우로 움직이는 mouseX 값을 y축에 대입하는 이유는
        // 마우스를 좌/우로 움직일 때 카메라도 좌/우를 보려면 카메라 오브젝트의
        // y축의 회전되어야 하기 때문
        eulerAngleY += mouseX * rotateSpeedX;
        // 감은 개념으로 카메라가 위/아래를 보려면 카메라 오브젝트의 x축이 회전한다
        eulerAngleX -= mouseY * rotateSpeedY;

        // x축 회전 값의 경우 아래, 위를 볼 수 있는 제한 각도가 설정되어 있다
        eulerAngleX = ClampAngle(eulerAngleX, limitMinX, limitMaxX);

        // 실제 오브젝트의 쿼터니온 회전에 적용
        transform.rotation = Quaternion.Euler(eulerAngleX, eulerAngleY, 0);
    }

    // 최대 최소 각도를 설정하여 기정한 값을 넘기지 않도록 만든다
    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;

        // Mathf.Clamp()를 이용해 angle이 min <= angle <= max를 유지하도록 한다
        return Mathf.Clamp(angle, min, max);
    }
}

PlayerController

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

public class PlayerController : MonoBehaviour
{
    private Movement3D movement3D;
    [SerializeField]
    private KeyCode jumpKeyCode = KeyCode.Space;
    [SerializeField]
    private CameraController cameraController;

    private void Awake()
    {
        movement3D = GetComponent<Movement3D>();
    }

    private void Update()
    {
        // x, z 방향 이동
        float x = Input.GetAxisRaw("Horizontal"); // 방향키 좌/우 움직임
        float z = Input.GetAxisRaw("Vertical"); // 방향키 위/아래 움직임

        movement3D.MoveTo(new Vector3(x, 0, z));

        // 점프키(스페이스)를 눌러 y축 방향으로 뛰어오르기
        if (Input.GetKeyDown(jumpKeyCode))
        {
            movement3D.JumpTo();
        }

        float mouseX = Input.GetAxis("Mouse X"); // 마우스 좌/우 움직임
        float mouseY = Input.GetAxis("Mouse Y"); // 마우스 위/아래 움직임

        cameraController.RotateTo(mouseX, mouseY);
    } 
}
profile
즐겁게 살자

0개의 댓글