Zooming limit in unity mobile. Perspective Camera

331 Views Asked by At

I'm trying to limit the zoom value of my game to a minimum and a maximum but i can't get how to do it! I've been trying by limiting the Y according to the zoom factor but it does not work properly, because when it reaches the limit, it starts flickering, like it hit an obstacle. I found some things that can solve this problem by using the fieldofview, but I need it to work with the Y limitations! I also want to add a panning limit, so that the player won't be able to see the end of the map but I didn't get there yet.

Anyways, here is the code i'm using and would appreciate if someone could help!

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

class ScrollAndPinch : MonoBehaviour
{
#if UNITY_IOS || UNITY_ANDROID
  public Camera Camera;
  public bool Rotate;
  protected Plane Plane;

  public float scrollSpeed;
  public float rotateSpeed;
  public float zoomSpeed;

  public float zoomMinY;
  public float zoomMaxY;

  public float camsummer;

  Vector3 pos;
  private Vector3 velocity = Vector3.zero;


  private void Awake()
  {
    if (Camera == null)
      Camera = Camera.main;

    Rotate = true;

    scrollSpeed = 50f;
    rotateSpeed = 50f;
    zoomSpeed = 1f;

    zoomMinY = 50f;
    zoomMaxY = 200f;

    camsummer = 0.1f;

    pos = new Vector3(0f, 0f, 0f);

  }

  private void Update()
  {

    //Update Plane
    if (Input.touchCount >= 1)
      Plane.SetNormalAndPosition(transform.up, transform.position);

    var Delta1 = Vector3.zero;
    var Delta2 = Vector3.zero;

    //Scroll
    if (Input.touchCount == 1)
    {
      Delta1 = PlanePositionDelta(Input.GetTouch(0));
      if (Input.GetTouch(0).phase == TouchPhase.Moved)
        Camera.transform.Translate(Delta1 * scrollSpeed * Time.deltaTime, Space.World);
    }

    //Pinch
    if (Input.touchCount == 2)
    {
      var pos1 = PlanePosition(Input.GetTouch(0).position);
      var pos2 = PlanePosition(Input.GetTouch(1).position);
      var pos1b = PlanePosition(Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition);
      var pos2b = PlanePosition(Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition);

      //calc zoom to be done relative to the distance moved between the fingers
      var zoom = (Vector3.Distance(pos1, pos2) /
                 Vector3.Distance(pos1b, pos2b));

      //edge case (Bad calculation)
      if (zoom == 0 || zoom > 10)
        return;

      //Move cam amount the mid ray. This is where the zoom is applied

      // Vector3 pos = Camera.transform.position;
      // pos.y = Mathf.Clamp(pos.y, zoomMinY, zoomMaxY);
      // Camera.transform.position = Vector3.Lerp(pos1, Camera.transform.position, (1 / zoom));
      // Camera.transform.position = pos;



      if (Camera.transform.position.y < zoomMinY | Camera.transform.position.y > zoomMaxY)
      {
        // Camera.transform.position = pos;
        Camera.transform.position = Vector3.SmoothDamp(Camera.transform.position, pos, ref velocity, camsummer);
        // Camera.transform.position = Vector3.LerpUnclamped(Camera.transform.position, pos, camsummer);
        // for (int i = 0; i < 1000; i++)
        // {
        // }

      }
      else if (Camera.transform.position.y >= zoomMinY && Camera.transform.position.y <= zoomMaxY)
      {
        pos = Camera.transform.position;
        Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, (1 / zoom));
        //This is where the rotation is applied
        if (Rotate && pos2b != pos2)
          Camera.transform.RotateAround(pos1, Plane.normal,
            Vector3.SignedAngle(pos2 - pos1, pos2b - pos1b, Plane.normal) * rotateSpeed * Time.deltaTime);
      }
      // pos.y = zoomMinY;
    }



    // if (Camera.transform.position.y > 200)
    // {
    //   zoomMaxY.y = 200;
    //   Camera.transform.position = zoomMaxY;
    // }
    // else if (Camera.transform.position.y < 50)
    // {
    //   zoomMinY.y = 50;
    //   Camera.transform.position = zoomMinY;
    // }
    // else if (Camera.transform.position.y >= 50 && Camera.transform.position.y <= 200)
    // {
    //   Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, (1 / zoom));
    // }


    // Vector3 Cam = Mathf.Clamp(Camera.transform.position.y, zoomMinY.y, zoomMaxY.y);


    // if (Camera.transform.position.y > zoomMaxY || Camera.transform.position.y < zoomMinY)
    // {
    //   Vector3 camLimit = Camera.transform.position;
    //   camLimit.y = Mathf.Clamp(Camera.transform.position.y, zoomMinY, zoomMaxY);
    //   Camera.transform.position = camLimit;



    //   // Vector3 camLimit = Camera.transform.position;
    //   // camLimit = (transform.position.);
    //   // Camera.transform.position = camLimit;
    // }
    // else if (Camera.transform.position.y >= zoomMinY && Camera.transform.position.y <= zoomMaxY)
    // {
    //   Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, (1 / zoom));
    // }





  }

  protected Vector3 PlanePositionDelta(Touch touch)
  {
    //not moved
    if (touch.phase != TouchPhase.Moved)
      return Vector3.zero;

    //delta: How far have we moved from A to B by sliding the finger
    var rayBefore = Camera.ScreenPointToRay(touch.position - touch.deltaPosition);
    var rayNow = Camera.ScreenPointToRay(touch.position);
    if (Plane.Raycast(rayBefore, out var enterBefore) && Plane.Raycast(rayNow, out var enterNow))
      return rayBefore.GetPoint(enterBefore) - rayNow.GetPoint(enterNow);

    //not on plane
    return Vector3.zero;
  }

  protected Vector3 PlanePosition(Vector2 screenPos)
  {
    //position
    var rayNow = Camera.ScreenPointToRay(screenPos);
    if (Plane.Raycast(rayNow, out var enterNow))
      return rayNow.GetPoint(enterNow);

    return Vector3.zero;
  }

  private void OnDrawGizmos()
  {
    Gizmos.DrawLine(transform.position, transform.position + transform.up);
  }
#endif
}

And to make it easier to see, this is the part I am struggling to make it work.

if (Camera.transform.position.y < zoomMinY | Camera.transform.position.y > zoomMaxY)
      {
        Camera.transform.position = Vector3.SmoothDamp(Camera.transform.position, pos, ref velocity, camsummer);


      }
      else if (Camera.transform.position.y >= zoomMinY && Camera.transform.position.y <= zoomMaxY)
      {
        pos = Camera.transform.position;
        Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, (1 / zoom));
        //This is where the rotation is applied
        if (Rotate && pos2b != pos2)
          Camera.transform.RotateAround(pos1, Plane.normal,
            Vector3.SignedAngle(pos2 - pos1, pos2b - pos1b, Plane.normal) * rotateSpeed * Time.deltaTime);
      }
1

There are 1 best solutions below

2
Bean5 Music On

Does this happen when the camera gets close to an object? If so change the near clip plane distance on your camera to.near = 0

That should stop it from not showing the gameobject, if ur camera keeps moving it might cause the flickering because it clips in and out of the near clip plane