WokerHead
WokerHead

Reputation: 967

Unity: How to limit the zooming out of the camera

Using Unity 2018.3

This camera script allows the user to zoom in and out and move the camera with touch around.

On Start() the script takes the cameras current position and saves it as the out of bounds limit. So if the player is zoomed in and moves the camera to the side, the camera will stop when it reaches the bounds limit.

My problem is that currently the user can zoom out all they want, causing the camera to get shaky as the script is trying to relocate the camera but it doesn't stop the user from increasing the orthographicSize.

How do I limit the user from zooming out passed the out of bound limit it got on Start()?

public class ControlCamera : MonoBehaviour
{

    private Vector2?[] oldTouchPositions = {
        null,
        null
    };

    private Vector2 oldTouchVector;

    private float oldTouchDistance;

    private Vector3 bottomLeft;
    private Vector3 topRight;

    private float cameraMaxY;
    private float cameraMinY;
    private float cameraMaxX;
    private float cameraMinX;

    public float maxZoom;
    public float minZoom;

    private void Start()
    {
        //  Set max camera bounds
        topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
        bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));
        cameraMaxX = topRight.x;
        cameraMaxY = topRight.y;
        cameraMinX = bottomLeft.x;
        cameraMinY = bottomLeft.y;
    }

    private void Update()
    {
        //  No touches
        if (Input.touchCount == 0)
        {
            oldTouchPositions[0] = null;
            oldTouchPositions[1] = null;
        }
        //  1 Touch
        else if (Input.touchCount == 1)
        {
            if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
            {
                oldTouchPositions[0] = Input.GetTouch(0).position;
                oldTouchPositions[1] = null;
            }
            else
            {
                Vector2 newTouchPosition = Input.GetTouch(0).position;

                transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * GetComponent<Camera>().orthographicSize / GetComponent<Camera>().pixelHeight * 2f));

                oldTouchPositions[0] = newTouchPosition;
            }
            //  2 touches or more
        } else {

            if (oldTouchPositions[1] == null)
            {
                oldTouchPositions[0] = Input.GetTouch(0).position;
                oldTouchPositions[1] = Input.GetTouch(1).position;
                oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
                oldTouchDistance = oldTouchVector.magnitude;

            } else {

                Vector2 screen = new Vector2(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight);

                Vector2[] newTouchPositions = {
                    Input.GetTouch(0).position,
                    Input.GetTouch(1).position
                };
                Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
                float newTouchDistance = newTouchVector.magnitude;

                transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y));
                GetComponent<Camera>().orthographicSize *= oldTouchDistance / newTouchDistance;
                transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y);

                oldTouchPositions[0] = newTouchPositions[0];
                oldTouchPositions[1] = newTouchPositions[1];
                oldTouchVector = newTouchVector;
                oldTouchDistance = newTouchDistance;

                // --------------------------------------------------------------->>

                //  Control Zoom In
                if (GetComponent<Camera>().orthographicSize > minZoom)
                {
                    //
                }

                //  Control Zoom Out
                if (GetComponent<Camera>().orthographicSize < maxZoom)
                {
                    //
                }

                // --------------------------------------------------------------->>
            }
        }

        //  Check if camera is out-of-bounds, if so, move back in-bounds
        topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
        bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));

        if (topRight.x > cameraMaxX)
        {
            transform.position = new Vector3(transform.position.x - (topRight.x - cameraMaxX), transform.position.y, transform.position.z);
        }

        if (topRight.y > cameraMaxY)
        {
            transform.position = new Vector3(transform.position.x, transform.position.y - (topRight.y - cameraMaxY), transform.position.z);
        }

        if (bottomLeft.x < cameraMinX)
        {
            transform.position = new Vector3(transform.position.x + (cameraMinX - bottomLeft.x), transform.position.y, transform.position.z);
        }

        if (bottomLeft.y < cameraMinY)
        {
            transform.position = new Vector3(transform.position.x, transform.position.y + (cameraMinY - bottomLeft.y), transform.position.z);
        }
    }
}

Upvotes: 2

Views: 2002

Answers (1)

derHugo
derHugo

Reputation: 90580

  1. You should not use GetComponent repeatedly especially not in Update or any repeatedly called method as this creates a lot unnecessary overhead. Instead get it once

    private Camera camera;
    
    private void Awake()
    {
        camera = GetComponent<Camera>();
    }
    

    and reuse that reference -> Everywhere replace GetComponent<Camera>() width camera

  2. If my understanding is correct, orthographicSize is half of the height of the camera in world units.

    Since you already get topRight and bottomLeft in world coordinates you should be able to calculate an orthographicSize

    maxZoom = (CameraMaxY - CameraMinY) / 2.0f;
    

    however, if anyway you want the original zoom to be the max zoom you could also simply store the original zoom like

    maxZoom = camera.orthographicSize;
    
  3. And later you can simply clamp the value like

    camera.orthographicSize = Mathf.Clamp(
        camera.orthographicSize * oldTouchDistance / newTouchDistance, 
        minZoom, 
        maxZoom);
    

    -> no need for extra if checks

Upvotes: 4

Related Questions