개발/Unity

유니티 - 멀티 터치 드래그를 이용하여 카메라 줌 인 / 아웃 (Camera Zoom in / out with Multi Touch Drag)

피로물든딸기 2023. 7. 15. 19:10
반응형

Unity 전체 링크

 

참고

→ 시네머신 튜토리얼 링크 (시네머신을 이용하여 카메라 간편하게 조작하기)

- 마우스 스크롤로 카메라 줌 인 / 아웃

- OpenGL로 멀티 터치 이펙트 만들기

- 멀티 터치 드래그로 오브젝트 크기 변경하기

 

멀티 터치 이펙트를 적용한 후, 멀티 터치를 드래그 했을 때, 카메라가 줌 인 / 줌 아웃이 되도록 해보자.


카메라 줌 인 / 줌 아웃

 

마우스 스크롤로 카메라를 줌 인 / 아웃하였을 때,

fieldOfView를 변경하거나 카메라가 향한 방향으로 앞 / 뒤로 이동하였다.

여기서는 카메라의 위치를 변경시킨다.

 

먼저 카메라에 있는 MobileTouch.cs에서 radius를 조금 줄이고, zoomSpeed 변수를 추가한다.

    float radius = 0.02f;
    float zoomSpeed = 1.0f;

 

Update에서는 터치 카운트가 2인 경우, 현재와 이전 위치의 차이를 빼서 카메라의 위치를 변경시켰다.

Input.GetTouch의 position에서 deltaPosition을 빼면 이전 터치 위치를 알 수 있다.

만약 diffprev - curr로 변경하면 두 손을 오므릴 때, 줌 인이 된다.

    void Update()
    {
        if(Input.touchCount == 2)
        {
            Vector2 prevPos0 = Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition;
            Vector2 prevPos1 = Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition;

            float prevDistance = (prevPos0 - prevPos1).magnitude;
            float currDistance = (Input.GetTouch(0).position - Input.GetTouch(1).position).magnitude;

            float diff = currDistance - prevDistance;

            Vector3 cameraDirection = this.transform.localRotation * Vector3.forward;

            this.transform.position += cameraDirection * Time.deltaTime * diff * zoomSpeed;
        }

        ...
    }

 

또는 fieldOfView를 변경해도 된다.

Camera.main.fieldOfView += diff * Time.deltaTime * zoomSpeed;

 

안드로이드 빌드 후, 멀티 터치를 드래그 해보자.

터치된 위치의 크기에 따라 카메라의 위치가 변경된다.

 

전체 코드는 다음과 같다.

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

public class MobileTouch : MonoBehaviour
{
    Material mat;
    bool touchFlag;
    List<Vector3> touchPosList;

    int numberOfTriangle = 10;
    float radius = 0.02f;
    float zoomSpeed = 1.0f;

    void makeCircle(Vector3 touchPos, Color color)
    {
        GL.Color(color);

        List<Vector3> pos = new List<Vector3>();

        for (int i = 0; i < numberOfTriangle; i++)
        {
            float angle = i * (Mathf.PI * 2.0f) / numberOfTriangle;

            Vector3 dot = (new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0)) * radius;

            float width = (float)Screen.width;
            float height = (float)Screen.height;

            if (width > height)
            {
                dot.x = dot.x * height / width;
            }
            else
            {
                dot.y = dot.y * width / height;
            }

            pos.Add(dot + touchPos);
        }

        for (int i = 0; i < numberOfTriangle - 1; i++)
        {
            GL.Vertex3(touchPos.x, touchPos.y, 0);
            GL.Vertex3(pos[i + 1].x, pos[i + 1].y, 0);
            GL.Vertex3(pos[i].x, pos[i].y, 0);
        }

        GL.Vertex3(touchPos.x, touchPos.y, 0);
        GL.Vertex3(pos[0].x, pos[0].y, 0);
        GL.Vertex3(pos[numberOfTriangle - 1].x, pos[numberOfTriangle - 1].y, 0);
    }
    
    void OnPostRender()
    {
        if (!mat)
        {
            Debug.LogError("Please Assign a material on the inspector");
            return;
        }

        if (touchFlag)
        {
            GL.PushMatrix();
            mat.SetPass(0);

            GL.LoadOrtho();

            GL.Begin(GL.TRIANGLES);

            int touchCount = touchPosList.Count;

            Color[] colorSet = new Color[] { Color.red, Color.green, Color.blue };

            for (int i = 0; i < touchCount; i++)
                makeCircle(touchPosList[i], colorSet[i % 3]);

            GL.End();
            GL.PopMatrix();
        }
    }

    void Start()
    {
        mat = new Material(Shader.Find("Draw/Quads"));
    }

    void Update()
    {
        if(Input.touchCount == 2)
        {
            Vector2 prevPos0 = Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition;
            Vector2 prevPos1 = Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition;

            float prevDistance = (prevPos0 - prevPos1).magnitude;
            float currDistance = (Input.GetTouch(0).position - Input.GetTouch(1).position).magnitude;

            float diff = currDistance - prevDistance;

            Vector3 cameraDirection = this.transform.localRotation * Vector3.forward;

            this.transform.position += cameraDirection * Time.deltaTime * diff * zoomSpeed;
        }

        if (Input.GetMouseButton(0))
        {
            touchPosList = new List<Vector3>();

            int touchCount = Input.touchCount;
            for (int i = 0; i < touchCount; i++)
            {
                Vector3 inputPos = Input.GetTouch(i).position;

                Vector3 mousePos
                    = new Vector3(inputPos.x, inputPos.y, -Camera.main.transform.position.z);

                Vector3 touchPos = Camera.main.ScreenToViewportPoint(mousePos);

                touchPosList.Add(touchPos);
            }

            touchFlag = true;
        }
        else
        {
            touchFlag = false;
        }
    }
}

 

반응형