화면 밖 적 화살표가 정확한 이유

액션 게임이나 슈팅 게임을 하다 보면 가장자리에 작은 화살표가 뜨면서 “적이 저쪽에 있다”고 알려주는 장면을 자주 접하는데요.

이 글은 그 화살표가 화면 테두리 위 어디에 찍혀야 실제 방향과 어긋나지 않는지를 다룹니다. 가장 쉽게 떠올리는 방식인 x좌표와 y좌표를 따로 잘라내는 방법이 어디서 틀리는지, 그리고 화면 중심에서 광선을 쏘는 방식이 왜 틀리지 않는지를 코드로 돌려 나온 숫자와 함께 정리해봤습니다.

모서리에 몰리는 화살표

화면 밖에 있는 적의 위치를 테두리 안으로 끌어오는 가장 간단한 방법은 좌표를 범위 안으로 잘라내는 것인데요. 적의 x가 화면 너비를 넘으면 오른쪽 끝으로 y가 화면 높이를 넘으면 아래 쪽 끝으로 붙이면 끝납니다.

코드는 두 줄이면 충분하고 화면 안쪽으로 한 번에 들어오니 겉보기에도 그럴듯합니다. 문제는 이 방식이 화면 중심에서 적을 바라보는 방향을 전혀 고려하지 않는다는 점입니다. 적이 오른쪽 아래 멀리 있으면 x도 y도 한계를 넘어서 두 값이 동시에 잘리게 되고 결과로 나온 점은 어느 방향에서 오든 똑같이 모서리 한 곳에 찍히게 됩니다.

화면 밖을 알리던 오래된 방법

화면 밖에 대상을 알리는 문제는 게임보다 먼저 인터페이스 연구에서 다루어졌습니다. 2003년 CHI 학회에서 발표된 파텍 바우디시와 루스 로젠홀츠의 논문 “HALO”는 화면 밖 대상마다 그 대상을 중심으로 한 큰 원을 그려서 원의 일부가 화면 가장자리 안으로 비쳐 들어오게 하는 기법을 제안했습니다.

호가 휘어진 정도를 보면 대상이 얼마나 먼지까지 읽어낼 수 있다는 발상입니다. 이 논문이 풀어내는 문제는 화살표와 다르나 화면 안에는 없는 대상을 화면 가장자리의 그림 한 조각으로 알려준다는 목표와 동일합니다. 다만 그림 한 조각이 가리키는 방향이 틀리면 그 조각은 오히려 방해가 된다는 점에서 화살표는 방향의 정확도가 가장 중요한 요소가 됩니다.

중심에서 광선을 쏜다

방향을 지키는 방법은 예상보다 단순한데요. 화면 중심에서 적까지 직선을 긋고 그 직선이 테두리 사각형과 처음 만나는 점에 화살표를 찍으면 됩니다.

중심에서 적까지의 벡터를(dx, dy)라 칭하고 테두리 사각형의 중심에서 가장자리까지의 절반 너비를 hx, 절반 높이를 hy라 칭하면 직선이 좌우 가장자리에 닿기까지 필요한 배율은 |hx|/|dx|이고 위아래 가장자리까지는 hy/|dy|입니다.

둘 중 작은 쪽이 먼저 닿는 면이므로 작은 배율을 벡터에 곱한 점이 곧 화살표의 위치가 되는 겁니다. 화면 가장자리에서 40픽셀 안쪽에 사각형을 하나 더 그려두고 그 사각형에 대해 계산하면 화살표가 잘려지지 않고 화면 안에 온전히 들어오게 됩니다. 방향 벡터에 하나의 스칼라만 곱하니 방향이 바뀔 이유가 없는 겁니다.

카메라 뒤의 적은 반대편에 뜬다

2D 게임이라면 여기까지로 충분하다고 할 수 있지만 3D 게임에서는 적의 월드 좌표를 먼저 화면 좌표로 바꿔야 합니다. 유니티의 Camera.WorldToScreenPoint 문서는 화면 왼쪽 아래 픽셀을 (0,0), 오른쪽 위 픽셀을 (너비-1, 높이-1)로 정의하고 z 값에 카메라로부터의 거리를 담아 돌려준다고 안내합니다.

대상이 카메라의 시야 밖에 있으면 화면 밖의 좌표가 나온다는 설명도 함께 실려있죠. 이 문서는 카메라 뒤쪽에 있는 점이 어떻게 되는지를 따로 다루지는 않습니다. 그래서 원근 투영 공식을 직접 계산해서 체크해봤습니다. 수직 시야각 60도, 1920×1080 화면에서 카메라 앞 10m, 오른쪽 5m 지점의 적은 가로 1,428픽셀 위치로 찍혔습니다. 같은 지점을 카메라 뒤 10m로 옮기자 가로 492픽셀로 찍혔습니다. 오른쪽에 있는 적이 왼쪽에 있는 것처럼 보이는 겁니다. z가 음수인 점은 좌표를 그대로 사용하지 않고 방향을 뒤집어서 처리해야 한다는 의미입니다.

24방향으로 돌려봤다

1920×1080 화면에 가장자리 40픽셀의 여백을 두고 화면 중심에서 1,500픽셀 떨어진 곳에 15도 간격으로 적 24마리를 세워봤습니다. 그리고 두 방식으로 각각 화살표 위치를 계산한 뒤 화면 중심에서 화살표를 본 방향이 적을 본 방향과 몇 도 어긋나는지 재봤습니다. 광선 방식은 24곳 모두 오차가 0도였는데요. 좌표를 따로 자른 방식은 평균 12.5도, 가장 큰 곳은 26.3도가 어긋났습니다.

오차는 상하좌우에서 멀어질수록 커지다가 60도와 120도 방향에서 가장 컸습니다. 서로 다른 방향인데 같은 지점으로 모인 경우도 있었습니다. 30도와 45도 방향의 적이 오른쪽 아래 모서리 한 점으로 겹쳐졌고 다른 세 모서리에서도 똑같이 두마리씩 겹쳐서 24곳이 20곳으로 줄어들었습니다.

화면 밖 적 화살표 위치 비교

멀수록 더 크게 틀렸다

24방향은 일부러 고른 배치라서 우연일 수도 있습니다. 그래서 화면 밖 어디든 무작위로 적을 뿌려서 한 번 더 체크해봤습니다. 가로 -3,000에서 4,920, 세로 -2000에서 3,080, 범위에 점을 20만 개 찍고 화면 안에 들어온 점을 걸러내자 18만 9,768개가 남았습니다.

좌표를 따로 자른 방식은 평균 12.8도, 상위 5% 지점이 33.1도, 최대 41.5도 어긋났습니다. 10도 넘게 틀린 경우가 52.6%, 5도 넘게 틀린 경우가 74.8%였고 전체의 65.0%는 모서리 한 점에 붙어버렸습니다. 적이 멀수록 오차가 커지는 경향도 보였죠. 중심에서 1,200픽셀 떨어졌을 때 평균 9.4도였던 오차가 2,000픽셀에서 15.7도, 3,000픽셀에서 17.5도까지 늘었습니다. 적이 멀리 있을수록 화면 중심에서 본 방향과 테두리 위의 점이 이루는 각이 더 크게 벌어지는 것입니다. 광선 방식은 같은 18만 9.768개에서 오차가 사실상 0도였습니다.

화살표를 모서리에 몰아두면 방향 정보가 사라집니다. 적이 오른쪽 아래 어딘가에 있다는 것만 알려줄 뿐 몸을 몇 도 돌려야 하는지는 알려주지 못하기 때문입니다. 중심에서 쏜 광선은 적의 방향을 그대로 테두리 위로 옮겨 놓는 것이어서 화살표가 놓인 자리 자체가 곧 방향이었습니다.

댓글 남기기