본문 바로가기
Unity3D

[Unity3D] 게임 오브젝트의 마우스 방향으로 바라보기

by 로봇과나무 2014. 6. 29.
슈팅게임 등 마우스 포인터의 방향으로 게임 오브젝트가 회전을 해야 할 경우가 있습니다. 본인의 경우에는 간단하게 LookAt(); 이라는 함수를 써볼 생각했었으나, 약간의 오류를 발견하고 좀 더 나은 방법이 없을까 조금 고민을 하고는, 삼각함수를 이용하여 직접 계산하여 회전을 구하기로 하였습니다. (나중에라도 응용하시라고, 수학적인 기본 설명을 조금 달았습니다만, 혹시나 어렵게 생각하시는 분은 그냥 아래 코드 부분으로 바로 가셔도 됩니다. 하지만, 이해하고 있어야 응용할 수 있습니다.)
 
먼저, 삼각함수에 대한 기본 지식이 필요합니다. 본 삼각함수는 중학교 수학시간 에 처음 접한 것이지만 그 이후로 계속해서 여러 좌표와 각도를 구하는 기본적인 수학이 되어 자주 사용되고 있습니다. 다들 아시겠지만, 간단히 정리하면 다음과 같습니다.
 
아래와 같이 직각삼각형이 주어졌을때, 각 선분의 길이를 구하는 식과 각 θ(쎄타)를 구하는 식은 다음과 같습니다. 즉, 각 θ(쎄타)와 선분의 길이 하나만 알면, 삼각함수를 사용하여 나머지 한 변의 길이를 알수 있으며, 반대로 두 변의 길이를 알면 역삼각함수를 이용하여 두 변이 이루는 각 θ(쎄타)를 구할 수 있습니다. 역삼각함수의 이름은 아래 식과 같이 -1승의 형식으로 나타낼 수도 있으며, '아크사인(arcsin)', '아크코사인(arccos)', '아크탄젠트(arctan)'라고 불려집니다.

 

우리가 구하려고 하는 것은 게임 오브젝트를 마우스 포인터가 위치한 곳으로 바라보게 하는것이 목적입니다. 해당 목적을 이루기 위해서는 Unity3D의 좌표계에 대한 이해를 먼저해야 하겠습니다. 유니티의 평면 좌표계는 다음 그림과 같으며, 각도는 일반 각과 함께 라디안을 함께 사용하고 있습니다. 입력과 출력 시 일반 각을 기준으로 이루어 지는지, 라디안 값이 기준이 되는지 항시 주의 깊게 살펴봐야 할 것입니다. 3시방향을 기준으로 하며, 12시 방향은 일반 각으로는 90도이며, 라디안 값으로는 0.5 π(파이)에 해당합니다. 9시 방향의 각도는 180도가 됩니다. 또한 라디안 값으로는 π(파이)에 해당합니다. 6시 방향은 -90도 이며, 라디안으로는 -0.5 π(파이)가 됩니다.

Unity3D의 좌표계에 대한 이해를 하시면 여러 용도로 활용하실 수 있기 때문에 간단하게 그림으로 정리해 드렸습니다. 각을 나타내는 수치들이 어떻게 변화되는지 이해하시면 끝입니다. 

이제 코드를 자세하게 들여다 보세요. 이해하기 쉽게 주석을 가능한 많이 달았습니다만, 잘 이해가 안되시는 분은 그냥 가져다 사용해 보시면 아시게 될 것입니다. 

public class MouseRotation : MonoBehaviour {

	void Update () {

		//먼저 계산을 위해 마우스와 게임 오브젝트의 현재의 좌표를 임시로 저장합니다.
		Vector3 mPosition = Input.mousePosition; //마우스 좌표 저장
		Vector3 oPosition = transform.position; //게임 오브젝트 좌표 저장

		//카메라가 앞면에서 뒤로 보고 있기 때문에, 마우스 position의 z축 정보에 
		//게임 오브젝트와 카메라와의 z축의 차이를 입력시켜줘야 합니다.
		mPosition.z = oPosition.z - Camera.main.transform.position.z; 

		//화면의 픽셀별로 변화되는 마우스의 좌표를 유니티의 좌표로 변화해 줘야 합니다.
		//그래야, 위치를 찾아갈 수 있겠습니다.
		Vector3 target = Camera.main.ScreenToWorldPoint(mPosition);

		//다음은 아크탄젠트(arctan, 역탄젠트)로 게임 오브젝트의 좌표와 마우스 포인트의 좌표를
		//이용하여 각도를 구한 후, 오일러(Euler)회전 함수를 사용하여 게임 오브젝트를 회전시키기
		//위해, 각 축의 거리차를 구한 후 오일러 회전함수에 적용시킵니다.

		//우선 각 축의 거리를 계산하여, dy, dx에 저장해 둡니다.
		float dy = target.y - oPosition.y;
		float dx = target.x - oPosition.x;

		//오릴러 회전 함수를 0에서 180 또는 0에서 -180의 각도를 입력 받는데 반하여
		//(물론 270과 같은 값의 입력도 전혀 문제없습니다.) 아크탄젠트 Atan2()함수의 결과 값은 
		//라디안 값(180도가 파이(3.141592654...)로)으로 출력되므로
		//라디안 값을 각도로 변화하기 위해 Rad2Deg를 곱해주어야 각도가 됩니다.
		float rotateDegree =  Mathf.Atan2(dy, dx)*Mathf.Rad2Deg;

		//구해진 각도를 오일러 회전 함수에 적용하여 z축을 기준으로 게임 오브젝트를 회전시킵니다.
		transform.rotation = Quaternion.Euler (0f, 0f, rotateDegree);
	}
}

사용법은 마우스의 방향에 따라 회전하고자 하는 게임 오브젝트에 컴포넌트로 등록하시면 됩니다. 참고로 본 코드는 카메라가 z축을 방향을 보고 위치해 있는 좌표을 기준으로 설명 된 것입니다. 카메라가 위에서 아래 방향으로 내려보고 싶다면 마우스의 축과 게임 오브젝트의 좌표 축이 맞지 않아 축에 대한 변경을 하셔야 할 것입니다.

모쪼록 많은 분들에게 도움이 되었으면 합니다. 끝.