https://dnddkqja21.tistory.com/43
3rd Person Camera - Chaper 02. Follow Camera (3인칭 카메라 챕터2. 플레이어 추적 카메라)
https://dnddkqja21.tistory.com/42 1st, 3rd Person Camera - Chapter 01. Game Camera View. (1인칭 카메라, 3인칭 카메라 - 첫 번째 챕터. 게임 카메 https://dnddkqja21.tistory.com/41 Let's move my character Chapter2. More accurate calculations
dnddkqja21.tistory.com
지난 시간 플레이어를 추적하는 카메라에 이어서 이번 시간에는 카메라 회전을 구현해보겠습니다.
저는 추후에 조이스틱을 구현할 것이기 때문에 캔버스를 만들고 이동 조이스틱 영역과 회전 영역으로 나눌 예정입니다.
우선 캔버스를 하나 만들고 빈 오브젝트를 만든 뒤 Joystick Group이라고 명명합니다.
Joystick Group의 자식 오브젝트를 만든 후 Rotator라고 명명합니다.
Joystick Group과 Rotator 오브젝트 모두 앵커프리셋에서 스트레치로 설정해줍니다.
스트레치를 해주었기 때문에 모든 영역이 Rotator에 해당합니다.
저는 화면의 아무곳이나 터치하여 드래그를 할 시 카메라를 회전시켜보겠습니다.
public class CameraRotate : MonoBehaviour, IBeginDragHandler, IDragHandler
스크립트를 만든 후 CameraRotate라고 명명한 뒤 IBeginDragHandler, IDragHandler를 상속받습니다.
여기서 IBeginDragHandler, IDragHandler는 인터페이스라고 하는데요.
유니티에서는 유저들이 많이 사용하는 기능을 미리 구현해두었습니다.
우리는 가져와서 사용하되 각자의 성격에 맞게 조금씩만 커스텀하면 됩니다.
상속받은 두 인터페이스는 이름에서 유추해볼 수 있듯이 드래그와 관련된 기능입니다.
인터페이스가 궁금하신 분들은 검색을 해보시길 바라며 여기서는 따로 심도있게 다루지는 않겠습니다.
인터페이스는 메서드를 구현해야만 사용할 수 있습니다.
public void OnBeginDrag(PointerEventData beginPoint)
{
}
public void OnDrag(PointerEventData draggingPoint)
{
}
위와 같이 메서드를 구현해줍니다.
매개변수로 PointerEventData형을 받고 있습니다.
PointerEventData는 각 터치 이벤트의 정보를 포함하고 있습니다.
우리는 이제 코드 블럭 안에 드래그가 시작되었을 때, 드래그 중일 때 실행될 기능을 작성하기만 하면 됩니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class CameraRotate : MonoBehaviour, IBeginDragHandler, IDragHandler
{
[Header("카메라 암")]
[SerializeField]
Transform cameraArm;
[Header("카메라 회전 속도")]
[SerializeField]
float rotationSpeed = 5f;
[Header("카메라 상 회전 제한")]
[SerializeField]
float limitUpAngle = 5f;
[Header("카메라 하 회전 제한")]
[SerializeField]
float limitDownAngle = 70f;
Vector3 beginPos;
Vector3 dragPos;
float xAngle;
float yAngle;
float xAngleTemp;
float yAngleTemp;
void Start()
{
}
public void OnBeginDrag(PointerEventData beginPoint)
{
}
public void OnDrag(PointerEventData draggingPoint)
{
}
}
우리는 이전 시간에 카메라를 회전시키는 것이 아닌 카메라 암을 회전시키도록 구상을 해두었으므로 카메라 암을 담을 변수를 선언합니다.
이후에 카메라 회전 속도 및 카메라 회전 각도의 제한을 둘 변수도 선언합니다.
이후에 드래그를 시작한 곳의 좌표, 드래그 중인 곳의 좌표를 담을 변수인 beginPos, dragPos를 선언합니다.
마지막으로 카메라의 x,y각도를 담을 변수와 임시 변수를 생성해줍니다.
void Start()
{
xAngle = cameraArm.rotation.eulerAngles.x;
yAngle = cameraArm.rotation.eulerAngles.y;
}
스타트 함수에서 xAngle과 yAngle을 각각 카메라 암의 각도로 초기화합니다.
public void OnBeginDrag(PointerEventData beginPoint)
{
beginPos = beginPoint.position;
xAngleTemp = xAngle;
yAngleTemp = yAngle;
}
OnBeginDrag함수에서는 위와 같이 초기화를 해줍니다.
OnDrag함수를 구현하기 전에 알아야할 것이 있습니다.
2D인 Canvas는 x,y축으로 구성이 되어 있습니다.
우리는 좌우 또는 상하로 마우스 드래그를 할 수 있습니다.
다음으로 3D 오브젝트를 확인해봅시다.
우리는 각 축을 기준으로 회전을 시킬 것입니다.
만약 마우스로 좌우 드래그를 하면 캔버스에서는 x값이 변하지만 3D 오브젝트는 y축 기준으로 회전이 되어야 합니다.
반대로 마우스로 상하 드래그를 하면 캔버스에서는 y값이 변하고 3D 오브젝트는 x축 기준으로 회전이 되어야 합니다.
이를 명심하시기 바랍니다!
public void OnDrag(PointerEventData draggingPoint)
{
dragPos = draggingPoint.position;
yAngle = yAngleTemp + (dragPos.x - beginPos.x) * rotationSpeed * Time.fixedDeltaTime;
xAngle = xAngleTemp - (dragPos.y - beginPos.y) * rotationSpeed * Time.fixedDeltaTime;
// 카메라 상하 각도 제한
// 위에서 아래 보는 각도 (마우스 아래로)
if (xAngle > limitDownAngle) xAngle = limitDownAngle;
// 아래서 위를 보는 각도 (마우스 위로)
if (xAngle < limitUpAngle) xAngle = limitUpAngle;
cameraArm.rotation = Quaternion.Euler(xAngle, yAngle, 0.0f);
}
위에서 설명한 내용을 바탕으로 카메라 암의 회전에 대입을 해주었습니다.
카메라 상하 각도의 제한도 잊지말고 넣어주세요.
게임에서 카메라 회전의 제한을 두는 이유는 회전이 일정 각도 이상 진행되면 게임에서 보여주지 말아야할 부분까지 보일 수 있기 때문입니다. 또한 짐벌락 현상과도 깊은 연관이 있습니다. 이 포스팅에서는 이야기가 길어질 수 있기 때문에 다루지 않겠습니다.
Rotator 오브젝트에 Image 컴포넌트를 추가합니다.
Image 컴포넌트의 Color 속성에서 Alpha값을 0으로 수정합니다.
우리는 눈에 보이지 않는 투명한 Image를 마우스 드래그가 작동할 공간으로 사용할 것이기 때문입니다.
CameraRotate 스크립트를 Rotator 오브젝트에 추가해주세요!
에디터를 실행하여 확인해봅시다!
우리가 의도한 대로 마우스를 좌우로 드래그하면 좌우 회전, 상하로 드래그 하면 상하 회전을 합니다.
상하 회전 각도를 제한한 것도 정상적으로 작동하네요.
씬 탭도 같이 확인을 해보면 게임 탭에서 마우스를 드래그함에 따라 카메라 암이 플레이어를 기준으로 상하좌우로 회전하는 것을 확인하실 수 있습니다.
오늘은 카메라를 플레이어 기준으로 하고 상하좌우로 회전하는 기능을 만들어보았습니다.
다음 시간에는 플레이어 이동 로직의 보완과 카메라 줌인 줌아웃을 구현해보겠습니다.
오늘도 수고하셨습니다 :D