[Skill] 1인칭 카메라
in Unity
1인칭 카메라 시점을 구현해 볼 것이다.
우선 카메라 오브젝트가 플레이어를 따라다니도록 플레이어의 자식오브젝트로 넣어준다. 그리고 카메라 오브젝트의 트랜스폼을 리셋해주고 높이만 플레이어의 머리쪽에 위치할 수 있도록 조금 올려준다. 그럼 다음과 같은 그림이 된다.
카메라 오브젝트의 움직임은 플레이어 오브젝트의 자식 오브젝트로 넣어서 해결하였고 카메라의 회전에 대한 기능을 추가하기 위해 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에서 마우스의 움직임을 받아서 CameraController에 넘겨주면 된다. 다음과 같이 말이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Movement3D movement3D;
[SerializeField]
private CameraController cameraController;
void Awake()
{
movement3D = GetComponent<Movement3D>();
}
void Update()
{
float hAxis = Input.GetAxisRaw("Horizontal");
float vAxis = Input.GetAxisRaw("Vertical");
Debug.Log(Input.GetAxisRaw("Horizontal"));
movement3D.MoveTo(new Vector3(hAxis, 0, vAxis));
if (Input.GetKeyDown(KeyCode.Space))
{
movement3D.JumpTo();
}
//왼쪽 이동 :-1 , 대기 : 0 , 오른쪽 이동 : +1
float mouseX = Input.GetAxis("Mouse X"); //마우스 좌우 움직임
//아래로 이동 : -1, 대기 : 0 , 위로 이동 : +1
float mouseY = Input.GetAxis("Mouse Y");
cameraController.RotateTo(mouseX, mouseY);
}
}
그리고 Movement3D에서 플레이어의 움직임 방향을 정할 때 카메라가 바라보고 있는 시점을 기준으로 움직이게 해야하므로 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 moveDir; //이동 방향
[SerializeField]
private Transform cameraTransform;
private CharacterController characterController;
void Awake()
{
characterController = GetComponent<CharacterController>();
}
void Update()
{
//characterController.isGrounded
//발 위치의 충돌을 체크해 충돌이 되면 true,충돌이 되지 않으면 false값을 나타내는 변수.
if (characterController.isGrounded == false)
{
moveDir.y += gravity * Time.deltaTime;
}
characterController.Move(moveDir * moveSpeed * Time.deltaTime);
}
//PlayerController에서 호출하기 위해 public 설정
public void MoveTo(Vector3 dir)
{
//앞, 뒤, 좌, 우 움직임은 매개변수로 넘어온 값을 사용하고
//아래방향은 Update에서 계속 계산 되는 moveDir.y를 사용한다.
//카메라가 보고있는 방향을 기준으로 움직일 수 있도록 movedis를 생성한다.
Vector3 movedis=cameraTransform.rotation * dir;
moveDir = new Vector3(movedis.x, moveDir.y, movedis.z);
}
//PlayerController에서 호출하기 위해 public 설정
public void JumpTo()
{
if (characterController.isGrounded == true)//플레이어가 바닥에 붙어있으면
{
moveDir.y = jumpForce;
}
}
}
카메라의 Transform을 받아와 카메라의 회전값에 플레이어의 이동방향을 곱해준다.