
아침까지 기능 구현 병합 작업과 빌드 세팅 수정한다고 잠을 못자서 6시 이후에 바로 뻗어버렸다. 병합 작업이 생각보다 오래걸렸는데, 코드 컨벤션 단계에서 병합 과정을 위한 논의가 필요했을 것 같다.
다른 사람이 구현한 기능과 연계되는 작업의 경우 메서드 호출, 로직 구현 방식을 전달하고 전달받은 사람은 호환성을 위해 추가로 코드를 작성하는 과정이 필요하다고 생각한다.
여튼 우여곡절 끝에 병합 과정과 빌드를 마쳤고, 다행히 기능 상의 문제는 크게 없이 빌드 테스트를 진행할 수 있었다.
Build IssueList1List2이번에 공유하려는 것은 코드가 아닌 Cinemachine과 관련된 기능들이다. 백뷰 기준 마우스 입력 값에 따라 시점 변동을 구현하기 위해 Cinemachine을 사용했는데 꽤나 다양한 기능이 있어 소개하고 싶다.
Backview먼저 백뷰를 구현하기 위해서는 매우 간단하다.

Player 하위에 VirtualCamera를 생성한 뒤 Follow와 Look At을 Player로 설정하고 Body를 Transposer, Aim을 Same As Follow Target으로 설정한다.
이후 스크립트 상에서 마우스 입력 값에 따라 Player가 좌우로 회전하도록 해주면, 마우스 입력 값에 따라 플레이어가 좌우로 회전하고 카메라는 뒤에서 플레이어를 비추는 백뷰 구현이 끝난다.
다만 이 경우 마우스 y 입력 값에 따른 위 아래 회전이 불가능하기 때문에 단순한 백뷰 시점을 구현할 때 사용하면 될 것이다.
Backview + Input(MouseY)마우스 y 입력 값을 받기 위해서는 추가적인 작업이 필요한데 player 계층 구조는 그대로 두고 CinemachineVirtualCamera 컴포넌트의 Aim만 수정하면 된다.

Aim을 POV로 바꾸게 되면 카메라가 항상 Look At을 바라보지 않고, 마우스의 입력값을 통해 카메라의 회전을 제어할 수 있게 된다.
다만 위에서 이미 마우스 x 입력값에 따른 수평 회전 처리를 스크립트로 하고 있기 때문에 Horizontal Axis의 Input Axis Name을 비워 마우스 x 입력값을 적용시키지 않고, Vertical Axis 즉 수직 회전 처리를 마우스 y 입력값에 따라 추가로 처리하도록 구성한다.
수직 회전의 경우 카메라가 너무 많이 돌아가면 플레이어가 시야에서 벗어나기 때문에 Value Range를 적당한 값으로 설정할 필요가 있다.
다만 이 경우 단점이 있는데 카메라가 플레이어를 기준으로 위아래로 회전하는 것이 아닌 카메라 자체가 위 아래로 회전하기 때문에 플레이어가 시야에서 멀어진다는 단점이 있다.

Backview + Input(MouseY) + Look At Player그렇다면 플레이어를 항상 바라보지만, 수직 회전 처리를 하기 위해서는 어떻게 해야할까?
이를 구현하기 위해 시네머신 컴포넌트를 1시간 가까이 만졌지만, 정작 시네머신이 아닌 스크립트 상에서 회전 처리를 할 필요가 있었다.

위를 보면 시네머신이 아예 빠져있는 것을 볼 수 있은데 단순히 마우스 입력값에 따른 카메라의 회전 처리를 스크립트로 처리하면 플레이어를 중앙에 고정된 상태로 시점 구현이 가능하다.
public class PlayerCameraController : MonoBehaviour
{
[Header("References")]
[SerializeField] private Transform _player;
[SerializeField] private Transform _cameraRig;
[SerializeField] private float _minPitch;
[SerializeField] private float _maxPitch;
[Header("Mouse Config")]
[SerializeField][Range(0, 1)] private float _mouseSensitivityX;
[SerializeField][Range(0, 1)] private float _mouseSensitivityY;
public float OffsetX { get; private set; }
public float OffsetY { get; private set; }
private void Update()
{
OffsetX += Input.GetAxis("Mouse X") * _mouseSensitivityX;
_player.rotation = Quaternion.Euler(0f, OffsetX, 0f);
OffsetY += Input.GetAxis("Mouse Y") * _mouseSensitivityY;
OffsetY = Mathf.Clamp(OffsetY, _minPitch, _maxPitch);
_cameraRig.rotation = Quaternion.Euler(OffsetY, 0f, 0f);
}
}
수평 회전 처리는 마우스 x 입력 값에 따라 플레이어를 회전시키고, 수직 회전 처리는 마우스 y 입력 값에 따라 플레이어 하위에 위치한 CameraRig를 회전시키는 것이다. 이렇게 하면 다음과 같은 시점 구현이 완료된다.

물론 이렇게 시네머신을 사용하지 않고 구현이 가능하지만, 시네머신의 기능인 Cinemachine collider를 사용하지않아 벽과의 충돌로 인한 위치 보정을 적용하기위해서는 스크립트를 작성하거나 시네머신을 추가할 필요가 있다.
Backview + Input(MouseY) + Look At Player + Camera Collision Offset결국 우리가 원했던 최종 기능은 이렇게 4가지가 종합된 것이었기에 시네머신을 추가하여 기능 구현을 마무리했다.

스크립트는 위에서 작성한대로 두고, 시네머신을 추가하여 Follow, Look At으로 Player로 설정한 뒤 Add Extension으로 Cinemachine collider를 추가하면 벽과의 충돌을 감지하고 위치가 보정되도록 구현하는 것이 가능하다.
Collide Against를 Tag : Wall로 설정하고 Ignore Tag에 Player를 넣는 처리를 통해 구현을 마무리하면 끝이다.
결국 벽과의 충돌 보정 기능 구현을 먼저하려고 Cinemachine을 추가했다가 여기에 너무 매몰되어 기본적인 기능 구현에 시간이 걸린 케이스라서, 기능 구현 우선 순위를 제대로 정하고 작업에 들어갈 필요성을 느꼈다.