저번 [BA] 플레이어블 캐릭터의 시선 처리에 이어 포스팅해보도록 하겠습니다.
시선 처리를 작업한지 2주정도 되어 가는데요. 쉽지 않은 과정이었습니다. 저번 포스팅에 이어서 여러 가지 시도를 해보았습니다. 실패한 방법들이기 때문에 나열만 하고 넘어가도록 하겠습니다.
- 캐릭터의 발밑에 있는 회전 기준점을 목 부근으로 수정
- 좌표를 기준으로 회전하는 지점을 찾기 때문에 결과가 다를 게 없음
- 마우스 포인터부터 쏜 Ray와 캐릭터 정면 방향으로 쏜 Ray의 교차점을 바라보도록 시도
- 마우스 포인터부터 쏜 Ray는 마우스를 계속 따라다니는데 캐릭터 정면 방향으로 쏘는 Ray는 캐릭터가 마우스 포인터를 따라 회전한다는 전제 하에 움직이기 때문에 불가능
- 캐릭터의 목 부근에 보이지 않는 넓은 콜라이더를 배치하고 마우스 포인터부터 쏜 Ray가 해당 콜라이더와 충돌되는 지점을 바라보도록 시도
- 이외에도 다양한 자잘한 시도 실패…
수많은 시도 끝에 UnityEngine에 내장된 Plane 구조체를 활용해서 해결할 수 있었습니다. Plane 구조체와 관련된 내용은 따로 TIL로 기록할 예정입니다.
일단 몇 가지 조건은 있습니다. 앞선 포스팅처럼 플레이어의 머리 위치를 기준으로 회전하게 하고 싶다면 나열했던 실패 방법 중의 1번 방법은 적용이 되어야 합니다.
그리고 이 방법은 결국 실패 방법 중의 3번 방법과 원리는 비슷합니다. 목 부근에 Plane 구조체를 생성하고 마우스 포인터로부터 쏜 Ray가 Plane 구조체와 충돌되는 지점을 바라보도록 하는 것입니다.
다음은 충돌되는 지점을 구하는 코드입니다.
// 마우스 포인터로부터 Ray 생성
Ray ray = mainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
// 플레이어의 목 부근(0, 1.5, 0)에 Plane 구조체 생성
Plane plane = new Plane(Vector3.up, new Vector3(0, 1.5f, 0));
// 충돌된 곳까지의 거리
float rayLength;
if (plane.Raycast(ray, out rayLength))
{
// 충돌된 곳의 위치 반환
Vector3 point = ray.GetPoint(rayLength);
}
충돌되는 지점을 바라보게 하는 방법은 여러가지가 있습니다.
transform.LookAt(point);
가장 간단한 방법으로 볼 수 있죠. 다만 이 방법을 활용할 시 마우스 포인터가 캐릭터의 가까워지면 캐릭터가 의도되지 않은 회전을 보여줍니다.
마우스 포인터가 가까울 때의 예외 처리를 따로 해주어야 한다는 얘기죠.
// 플레이어의 위치와 바라봐야할 곳 사이의 방향 벡터
Vector3 look = point - transform.position;
transform.rotation = Quaternion.LookRotation(look);
간단한 방법이 있는데도 불구하고 Quaternion을 사용한 이유는 부드러운 움직임을 구현하기 위해서입니다.
Quaternion.Slerp를 활용하면 캐릭터가 마우스를 따라 휙휙 돌아가는 것보다는 부드럽게 따라오며 조금 더 자연스럽게 보이는 효과를 낼 수 있습니다.
Vector3 look = point - transform.position;
float t = 0.2f;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(look), t);
t의 값이 0에 가까울수록 시작점에 가까운 상태로 보간하고 1에 가까울수록 도착점에 가까운 상태로 보간합니다.
Slerp가 삼각함수를 계산하는 것이기 때문에 성능에 문제를 야기하지 않을까싶어서 Profiler로 비교해보았는데 딱히 문제는 없어보였습니다.
이 사진을 보시면 플레이어와 마우스 포인터 사이에 선이 하나 보이실 겁니다. 보는 지점을 Line Renderer 활용해서 시각화한 사진입니다.
어제 밤에 이 기능을 구현한 뒤에는 정말 만세를 불렀습니다...며칠동안 직접 코딩한 시간보다 키보드 앞에 앉아서 머리 싸멘 시간이 더 많았던 것 같은데 겨우 성공할 수 있었죠.
정말 이런저런 자료를 찾아보며 하다가 우연찮게 발견한 한 블로그에서 이 Plane을 활용한 해결방안을 발견해서 해결할 수 있었습니다. 링크는 Reference에 남겨놓도록 하겠습니다.