모바일 게임을 개발하다 가장 중요한 카메라 이동, 줌인 줌아웃에 대해 글을 써보려고 한다.

접촉되어있는 손가락의 개수를 감지하는 Input클래스의 touchCountInput.touchCount 이렇게 사용한다.

내가 쓴 코드는 줌인 줌아웃과 카메라 이동 코드가 있기에 touchCount가 1일때와 2일때로 나누었다.

if (Input.touchCount == 1)
{
	//터치 감지(카메라 이동)
}

화면에 접촉한 손가락의 순서를 감지하는 Input클래스의 GetTouch메소드는 Input.GetTouch(0) 이렇게 사용한다. (0), (1) …. 으로 첫번째, 두번째 순서를 나타낸다.

내가 쓴 코드는 오브젝트를 클릭하며 이동했을때 오브젝트가 회전하도록 구현했기에 TouchPhase 와 함께 사용했다.

TouchPhase에는 5가지가 존재한다.

Began터치가 시작되었을 때
Moved터치가 화면에서 움직일 때
Stationary터치 후 움직이지 않았을 때
Ended손가락을 뗐을 때(터치의 마지막 단계)
Cancled5개 이상의 터치 입력이 동시에 발생하여 추적을 취소했을 때
if (Input.touchCount == 1)
	{
		Touch touch = Input.GetTouch(0);

		if (touch.phase == TouchPhase.Began)
			{
	      //터치가 시작된 후 실행할 코드
			}
	}

위에서 언급했듯이 오브젝트를 클릭한 채로 터치를 이동하면 오브젝트를 회전하게, 아무것도 클릭하지 않고 터치를 이동하면 카메라를 이동하게 구현했다.

그래서 Raycast를 사용해 ray가 화면상에 존재하는 객체와 충돌했는지 반환하여 회전하도록 구현했다.

if (touch.phase == TouchPhase.Began)
{
    // 터치가 시작될 때 클릭된 오브젝트를 확인
    RaycastHit hit;
    Ray ray = Camera.main.ScreenPointToRay(touch.position);

    if (Physics.Raycast(ray, out hit))
    {
        if (hit.transform == otherObjectTransform)
        {
            isObjectSelected = true;
        }
        else
        {
            isObjectSelected = false;
        }
    }
}

if (isObjectSelected)
{
    // 오브젝트가 선택된 경우 오브젝트 회전
    switch (touch.phase)
    {
        case TouchPhase.Moved:

            Vector2 touchDelta = touch.deltaPosition;

            if (touchDelta.x != 0 || touchDelta.y != 0)
            {

                float rotationY = touchDelta.x * rotateSpeed;
                otherObjectTransform.Rotate(Vector3.up, rotationY, Space.World);
            }
            break;
    }
}
else
{
    // 오브젝트가 선택되지 않은 경우 카메라 이동
    switch (touch.phase)
    {
        case TouchPhase.Moved:
            Vector2 touchDelta = touch.deltaPosition;

            if (touchDelta.x != 0 || touchDelta.y != 0)
            {
                transform.Translate(-touchDelta.x * moveSpeed, -touchDelta.y * moveSpeed, 0);
            }
            break;
    }
}

하나씩 살펴보면 RaycastHit로 레이캐스트를 선언해주고 ScreenPointToRay 로 스크린 좌표를 인수로 넘겨주어 레이를 생성해준다.

Physics.Raycast는 ray가 화면상에 존재하는 객체와 충돌하면 true를 반환하고, out 파라미터로 RaycastHit를 리턴하며 객체 정보를 저장한다.

하지만 이 방법은 내가 원하던 방법을 구현하기엔 시간이 조금 걸릴 것 같아서 임시로 오브젝트가 회전하는 방법을 사용한 것이다.

→ 원래는 카메라가 오브젝트 주위를 회전하며 고정된 오브젝트를 다각도로 볼 수 있도록 구현하고 싶었다.

줌인 줌아웃 코드는 아래와 같이 작성했으며, 자세한 설명은 주석을 달아놨다

//접촉되어 있는 손가락 개수가 2일때(두 손가락을 터치했을때)
else if (Input.touchCount == 2)
{
    //첫번째 터치 정보 저장
    Touch touchZero = Input.GetTouch(0);
    //두번째 터치 정보 저장
    Touch touchOne = Input.GetTouch(1);

    //각각 터치의 이전 위치를 계산한다.
    Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
    Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

    //(목적지-현재위치).magnitude : 남은 거리
    //이전 위치와 현재 위치간의 거리를 계산한다
    float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
    float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

    //두 손가락 간의 거리를 계산한다
    float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;

    //orthographic모드일때
    if (GetComponent<Camera>().orthographic)
    {
        GetComponent<Camera>().orthographicSize += deltaMagnitudeDiff * orthoZoomSpeed;
        GetComponent<Camera>().orthographicSize = Mathf.Max(GetComponent<Camera>().orthographicSize, 0.1f);
    }
    //fieldOfView모드일때
    else
    {
        GetComponent<Camera>().fieldOfView += deltaMagnitudeDiff * perspectiveZoomSpeed;
        GetComponent<Camera>().fieldOfView = Mathf.Clamp(GetComponent<Camera>().fieldOfView, 0.1f, 179.9f);
    }
}

사용한 전체 코드는 아래와 같다. 이 또한 자세한 설명은 주석을 달아놨으니 참고!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TouchManager : MonoBehaviour
{
    //줌 속도 변수
    private float perspectiveZoomSpeed = 0.008f;
    private float orthoZoomSpeed = 0.0001f;

    //이동 속도
    private float moveSpeed = 0.001f;
    //회전 속도
    private float rotateSpeed = 0.1f;

    //회전할 오브젝트
    public Transform otherObjectTransform;

    private bool isObjectSelected = false; // 오브젝트가 선택되었는지 여부

    void Update()
    {
        // 오브젝트 클릭 여부에 따라 처리
        if (Input.touchCount == 1)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {
                // 터치가 시작될 때 클릭된 오브젝트를 확인
                RaycastHit hit;
                Ray ray = Camera.main.ScreenPointToRay(touch.position);

                if (Physics.Raycast(ray, out hit))
                {
                    //레이가 객체와 충돌했을때
                    if (hit.transform == otherObjectTransform)
                    {
                        isObjectSelected = true;
                    }
                    //충돌 X
                    else
                    {
                        isObjectSelected = false;
                    }
                }
            }

            //충돌이 나면
            if (isObjectSelected)
            {
                //터치 정보에 따라
                switch (touch.phase)
                {
                    //터치가 움직이면
                    case TouchPhase.Moved:
                        //터치의 이동량을 저장
                        Vector2 touchDelta = touch.deltaPosition;

                        //x또는 y가 하나라도 0이 아니면 회전(움직이면 회전)
                        if (touchDelta.x != 0 || touchDelta.y != 0)
                        {
                            //회전 수행
                            float rotationY = touchDelta.x * rotateSpeed;
                            otherObjectTransform.Rotate(Vector3.up, rotationY, Space.World);
                        }
                        break;
                }
            }

            //충돌X
            else
            {
                switch (touch.phase)
                {
                    //터치가 이동하면
                    case TouchPhase.Moved:
                        Vector2 touchDelta = touch.deltaPosition;

                        //터치가 이동했는지 확인
                        if (touchDelta.x != 0 || touchDelta.y != 0)
                        {
                            //카메라 터치의 이동량에 비례해 x와 y방향으로 이동하고, 이동량은 moveSpeed에 비례한다.
                            //-를 붙인 이유는 유니티 좌표계에서 카메라가 움직이는 방향을 반대로 하기 위해서임
                            transform.Translate(-touchDelta.x * moveSpeed, -touchDelta.y * moveSpeed, 0);
                        }
                        break;
                }
            }
        }

        //접촉되어 있는 손가락 개수가 2일때(두 손가락을 터치했을때)
        else if (Input.touchCount == 2)
        {
            //첫번째 터치 정보 저장
            Touch touchZero = Input.GetTouch(0);
            //두번째 터치 정보 저장
            Touch touchOne = Input.GetTouch(1);

            //각각 터치의 이전 위치를 계산한다.
            Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
            Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

            //(목적지-현재위치).magnitude : 남은 거리
            //이전 위치와 현재 위치간의 거리를 계산한다
            float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
            float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

            //두 손가락 간의 거리를 계산한다
            float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;

            //orthographic모드일때
            if (GetComponent<Camera>().orthographic)
            {
                GetComponent<Camera>().orthographicSize += deltaMagnitudeDiff * orthoZoomSpeed;
                GetComponent<Camera>().orthographicSize = Mathf.Max(GetComponent<Camera>().orthographicSize, 0.1f);
            }
            //fieldOfView모드일때
            else
            {
                GetComponent<Camera>().fieldOfView += deltaMagnitudeDiff * perspectiveZoomSpeed;
                GetComponent<Camera>().fieldOfView = Mathf.Clamp(GetComponent<Camera>().fieldOfView, 0.1f, 179.9f);
            }
        }
    }
}

0개의 댓글