[Unity] Cinemachine으로 모바일 3인칭 카메라 만들기Unity/C#2024. 7. 4. 23:35
Table of Contents
결과물부터 보자면 요런 느낌이다
이 글에서는 카메라에대한 구현만 기록하고 캐릭터 이동 관련은 기록하지 않는다
핵심
- Cinemachine으로 구현
- 화면을 드래그해서 카메라를 회전
- UI위 터치는 드래그 판정 무시
Cinemachine 설정
- `Virtual Camera`를 사용했다
- `Aim`의 타입은 `POV`로 사용하되 `Input Axis Name`은 비워뒀다
- 코드를 통해서 값을 조절할 것이다
- Follow와 LookAt은 캐릭터 머리쪽에 빈 오브젝트를 만들고 넣어줬다
마우스(포인터)가 UI위에 있는지 확인
- 앞으로의 구현을 위해서 필요하다
- 나는 이런 Tool코드는 `Static`클래스에다가 몰아넣는 편이다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Oni
{
public static class Tools
{
public static bool IsPointerOverUI()
{
PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
pointerEventData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerEventData, results);
for (int i = 0; i < results.Count; i++)
{
if (results[i].gameObject.layer == LayerMask.NameToLayer("UI"))
return true;
}
return false;
}
}
}
Unity의 드래그에대해서...
- Unity의 드래그 판정 방법은 여러가지인데 뭔가 통합이 덜된느낌이 좀 든다
- 방법 1 - `UnityEngine.EventSystems.IDragHandler`인터페이스를 상속받기
- 해당 인터페이스를 상속받으면 `OnDrag(PointerEventData)` 멤버 함수를 상속받는다
- `OnDrag`함수는 드래그가 일어나면 호출되지만 UI그래픽 오브젝트에게서만 작동한다
- 탈락!
- 방법 2 - `OnMouseDrag()` 예약 함수
- "`OnMouseDrag`는 사용자가 `GUIElement` 또는 `Collider`를 클릭하고 마우스 단추를 누르고 있는 경우 호출됩니다." 라고 한다
- 직접 테스트해보니 일반적인 UI에서는 작동 안하고 `Collider`가있는 오브젝트 위에서 드래그하면 호출이된다
- 아무튼 이 방법도 구현할 목표에 맞지않는다
- 탈락!
- 방법 3 - 마우스 버튼 다운, 홀드, 업으로 직접 판단해서 구현
- 이 방법을 사용할 것이다
- 방법 1 - `UnityEngine.EventSystems.IDragHandler`인터페이스를 상속받기
드래그 판정 구현
- 클래스 이름은 취향대로 지어주자
- 유니티 이벤트를 사용했으므로 `using UnityEngine.Events;`도 따로 추가해주자
- 주석으로 설명을 적었다
[SerializeField]
private bool isDragging; // 드래그 중인지 여부
[SerializeField]
private bool isTouchDownOnUI; // UI위에서 포인터 다운이 발생했는지 여부
[SerializeField]
private Vector3 dragStartPos; // 드래그를 시작한 좌표
[SerializeField]
private Vector3 previousDragPos; // 직전 드래그 좌표
[SerializeField]
private Vector3 dragVector; // 현재 좌표 - 직전 드래그 좌표(이동한 양)
public UnityEvent<Vector3> onBeginDrag; // 드래그 시작 이벤트
public UnityEvent<Vector3> onDrag; // 드래그 지속 이벤트
public UnityEvent onEndDrag; // 드래그 끝 이벤트
private void Update()
{
// 포인터 다운 감지
if(Input.GetMouseButtonDown(0))
{
// 드래그 시작 좌표 저장
dragStartPos = Input.mousePosition;
// 직전 드래그 좌표 초기화
previousDragPos = dragStartPos;
// 포인터가 UI위에있는지 확인하고 변수에 저장
isTouchDownOnUI = Tools.IsPointerOverUI();
}
if(Input.GetMouseButton(0))
{
// UI위에서 시작됐다면 드래그 무시
if (!isTouchDownOnUI)
{
// 현재 포인터 좌표
Vector3 currentMousePos = Input.mousePosition;
// 움직인 양 계산
dragVector = currentMousePos - previousDragPos;
// 처음이라면 onBeginDrag이벤트 실행
if(!isDragging)
{
isDragging = true;
onBeginDrag?.Invoke(dragVector);
}
// 처음이 아니라면 onDrag이벤트 실행
else
onDrag?.Invoke(dragVector);
// 직전 드래그 좌표 업데이트
previousDragPos = currentMousePos;
}
}
// 드래그 끝
if(Input.GetMouseButtonUp(0))
{
isDragging = false;
isTouchDownOnUI = false;
onEndDrag?.Invoke();
}
}
카메라 회전 구현
- 이제 드래그이벤트에 연결할 회전 함수를 만든다
- 파라미터로 들어오는 값을 넣어주는게 전부다
using UnityEngine;
using Cinemachine;
public class PlayerCameraRotator : MonoBehaviour
{
[SerializeField]
private CinemachineVirtualCamera cam; // Cinemachine카메라
[SerializeField]
private float multiply = 0.001f; // 보정값
public void OnDragUpdated(Vector3 dragVector)
{
// Horizontal, Vertical 입력값을 드래그값으로 넣어준다
cam.GetCinemachineComponent<CinemachinePOV>().m_HorizontalAxis.m_InputAxisValue = dragVector.x * multiply;
cam.GetCinemachineComponent<CinemachinePOV>().m_VerticalAxis.m_InputAxisValue = dragVector.y * multiply;
}
public void OnEndDrag()
{
// 드래그가 끝났으니 초기화한다
cam.GetCinemachineComponent<CinemachinePOV>().m_HorizontalAxis.m_InputAxisValue = 0f;
cam.GetCinemachineComponent<CinemachinePOV>().m_VerticalAxis.m_InputAxisValue = 0f;
}
}
- 아까 만든 드래그 이벤트에 연결해준다
- `onBeginDrag`이벤트는 사용하지 않았다
여담
나만 그런지 모르겠지만 Unity의 터치 입력 구현은 뭔가 직관성도 떨어지고 통합이 안된 느낌이다
그래서 할때마다 자꾸 헷갈린다 물론 나만 그럴 수도...
간단하게 `Cinemachine`카메라와 같이 작동하게 드래그 회전 카메라를 구현했다.
기본 카메라를 사용하면 좀 더 쉬웠을 수도 있지만 `Cinemachine`의 카메라 장애물 회피같은 플러그인을 사용할 수 없다.
여기서 좀 더 확장하면 캐릭터가 이동하는 방향으로 카메라가 서서히 에임을 맞추도록 구현하면 더 좋은 느낌이 될 것 같다.
끝
'Unity > C#' 카테고리의 다른 글
[C#] 빠르게 C# 단일 스크립트를 슥 작성하고 쇽 실행하는 법 (polyglot notebooks) (0) | 2024.06.27 |
---|---|
[Unity] JsonUtility.ToJson() 대신 Jobject.FromObject()를 쓰자 (1) | 2024.06.17 |
[Unity] Unity 3D Game Kit Lite템플릿 Damageable스크립트 분석 (1) | 2024.05.22 |
[Unity] 짧은 팁 - 사용중인 시스템 메모리 용량 구하기 (0) | 2024.04.29 |
[C#] DateTime에서 남은시간 계산하기 (0) | 2023.02.25 |