Camera Script - check for world's bounds

Hi, I have a script for moving my camera. I want the camera stays in the wold’s bounds and I check for this condition with raycast.
Everything is working well, BUT, when I move too fast (of slower on a device in witch the game has a LOW frame rate like iPad 1), the camera goes out of bounds, out of my world’s limit.

I dunno anymore how to do in order to fix this very annoying issue.
Have you got ideas?

Thanks

using UnityEngine;

using System.Collections;
 
public class CameraScript : MonoBehaviour
{
    public float speed = 10.0f;	
	public Vector2 position;
	
	private Transform cam;
	private Vector3 initPos;
	
	// Zoom
	
	private Camera zoomCamera;
    public float MINSCALE = 2.0F;
    public float MAXSCALE = 5.0F;
    public float minPinchSpeed = 5.0F;
    public float varianceInDistances = 5.0F;
    private float touchDelta = 0.0F;
    private Vector2 prevDist = new Vector2(0,0);
    private Vector2 curDist = new Vector2(0,0);
    private float speedTouch0 = 0.0F;
    private float speedTouch1 = 0.0F;
	
    // Use this for initialization

    void Start ()
    {
		cam = Camera.main.transform;
		zoomCamera = Camera.main;
		initPos = cam.position;
    }

    // Update is called once per frame	
	void Update()
	{
		UISprite joystickSprite = GameObject.Find("joystickSprite").GetComponent<UISprite>();
		UISprite joystickRing = GameObject.Find("joystickRing").GetComponent<UISprite>();
		UIJoystick j = GameObject.Find("Joystick").GetComponent<UIJoystick>();
		
		if(SV.control) {
			j.visible = true;
			joystickSprite.enabled = true;
			joystickRing.enabled = true;
		}
		else {
			j.visible = false;
			joystickSprite.enabled = false;
			joystickRing.enabled = false;
		}
	}
	
	void LateUpdate ()
	{
    	// Only if there are touches
    	if (Input.touches.Length == 1)
    	{
        	// Only work with the first touch
        	// and only if the touch moved since last update
        	if (Input.touches[0].phase == TouchPhase.Moved)
        	{
				if (!SV.control)
				{
	           		//position.x = 1 * Input.touches[0].deltaPosition.x * speed * Time.deltaTime;
    	       		//position.y = 1 * Input.touches[0].deltaPosition.y * speed * Time.deltaTime;
					
					float x = 0;
					float y = 0;
					
					if(Time.timeScale > 0) {
	            		//position.x = 1 * Input.touches[0].deltaPosition.x * speed * Time.deltaTime / Time.timeScale;
    	        		//position.y = 1 * Input.touches[0].deltaPosition.y * speed * Time.deltaTime / Time.timeScale;

						x = 1 * Input.touches[0].deltaPosition.x * speed * Time.deltaTime / Time.timeScale;
						y = 1 * Input.touches[0].deltaPosition.y * speed * Time.deltaTime / Time.timeScale;
					}
					else {
	           			position.x = 1 * Input.touches[0].deltaPosition.x * speed * Time.deltaTime;
    	       			position.y = 1 * Input.touches[0].deltaPosition.y * speed * Time.deltaTime;						
					}
					
					if(DynamicCheckBounds(x, y))
					{
						position.x = x;
						position.y = y;
						
						cam.Translate(new Vector3(position.x, 0, position.y), Space.World); // vector * speed
					}

					/*
					if (CheckBounds())
					{
						cam.Translate(new Vector3(position.x, 0, position.y), Space.World); // vector * speed
					}
					*/
					
					Vector3 pos = cam.position;
            		pos.y -= (cam.position.y - initPos.y) * 0.1f;
            		//assign new position to camera position
            		cam.position = pos;
				}
        	}			
		}
		
		// Zoom
		if (Input.touchCount == 2  Input.GetTouch(0).phase == TouchPhase.Moved  Input.GetTouch(1).phase == TouchPhase.Moved) 
		{
			curDist = Input.GetTouch(0).position - Input.GetTouch(1).position; //current distance between finger touches
			prevDist = ((Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition) - (Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition)); //difference in previous locations using delta positions
			touchDelta = curDist.magnitude - prevDist.magnitude;
			speedTouch0 = Input.GetTouch(0).deltaPosition.magnitude / Input.GetTouch(0).deltaTime;
			speedTouch1 = Input.GetTouch(1).deltaPosition.magnitude / Input.GetTouch(1).deltaTime;
			
			if ((touchDelta + varianceInDistances <= 1)  (speedTouch0 > minPinchSpeed)  (speedTouch1 > minPinchSpeed))
			{
				zoomCamera.fieldOfView = Mathf.Clamp(zoomCamera.fieldOfView + (5 * speed),30,90);
			}

			if ((touchDelta + varianceInDistances > 1)  (speedTouch0 > minPinchSpeed)  (speedTouch1 > minPinchSpeed))
			{
				zoomCamera.fieldOfView = Mathf.Clamp(zoomCamera.fieldOfView - (5 * speed),30,90);
			}
			
		}
    }

    //this method casts a ray against world limit mask with length of 5 units and returns a boolean,
    //which indicates whether movement is possible in that direction
    //on hit: world limit reached - return false, no hit: free space - return true
    private bool CheckBounds()
    {
        Vector3 forw = transform.forward * position.y * -1;
        Vector3 side = transform.right * position.x * -1;

        if (Physics.Raycast(cam.position, forw, 10, SV.worldMask))
        {
            return false;
        }
        else if (Physics.Raycast(cam.position, side, 10, SV.worldMask))
		{
            return false;
		}

        return true;
    }
	
    private bool DynamicCheckBounds(float x, float y)
    {
        Vector3 forw = transform.forward * y * -1;
        Vector3 side = transform.right * x * -1;

        if (Physics.Raycast(cam.position, forw, 10, SV.worldMask))
        {
            return false;
        }
        else if (Physics.Raycast(cam.position, side, 10, SV.worldMask))
		{
            return false;
		}

        return true;
    }
	
}

up

it looks like your using some type of physics to move the camera based on swiping the screen?
Usually when you have “tunneling” with physics, the easiest method is to check the next position of your object in the current update. IE: before you physically move object, ensure the move will succeed. If it succeeds, move the camera, if it won’t, find out the distance that will succeed, and move that distance instead.
I can’t see how your project is setup, but its likely that your transform.forward inside the DynamicBoundsCheck isn’t correct in detecting what you think its detecting. Try using some Debug.DrawRays.
I think you’d be better off creating a vector like this:
Vector3 camOffset = new Vector3(position.x, 0, position.y);

now you have the future position, the current position, and the offset your about to apply.
Physics.Raycast(cam.position, camOffset, camOffset.Magnitude, SV.worldMask)

and if that’s true, your going to hit something by moving the camera.
I would suggest creating a RaycastHit object and supplying the out params into the raycast so that you can get the distance of the collision. With that, you can update your position based on the collision distance.

A good example of all this coming together can be found by googling bullet scripts for unity.

thanks for your reply, i’ll try to draw ray… however the logic in DynamicCheckBounds is correct, I think. The problem happens only when the framer rate become SLOWER (like on the iPad 1)

here’s my dynamic check bounds, x and y are the new coordinates i’ll move to whether they are inside my world limit (i have a box collider on the world’s bounds)

    private bool DynamicCheckBounds(float x, float y)
    {
        Vector3 forw = transform.forward * y * -1;
        Vector3 side = transform.right * x * -1;
		
		//Camera.main.ViewportToScreenPoint
		/*
		Vector3 left = Camera.main.ScreenToWorldPoint(new Vector3(0, cam.position.y, cam.position.z));
		RaycastHit hit;
		if(!Physics.Raycast(cam.position, left, out hit)){
			return false;
		}
		*/
		
        if (Physics.Raycast(cam.position, forw, 10, SV.worldMask))
        {
            return false;
        }
        else if (Physics.Raycast(cam.position, side, 10, SV.worldMask))
		{
            return false;
		}

        return true;
    }

try making the box colliders on the outside bounds of the world much thicker then.

just tried, it doesn’t work :frowning:

I’m checking for detaTime now, I think if the deltaTime is > 1 I can reduce the new coordinates by multiplying them with a value < 1

I have to wait to see my friends with a lower iDevice for testing now! Let’s cross our finger

using UnityEngine;

using System.Collections;
 
public class CameraScript : MonoBehaviour
{
    public float speed = 10.0f;
	public Vector2 position;
	
	private Transform cam;
	private Vector3 initPos;
	
	// Zoom
	
	private Camera zoomCamera;
    public float MINSCALE = 2.0F;
    public float MAXSCALE = 5.0F;
    public float minPinchSpeed = 5.0F;
    public float varianceInDistances = 5.0F;
    private float touchDelta = 0.0F;
    private Vector2 prevDist = new Vector2(0,0);
    private Vector2 curDist = new Vector2(0,0);
    private float speedTouch0 = 0.0F;
    private float speedTouch1 = 0.0F;
	
    // Use this for initialization

    void Start ()
    {
		cam = Camera.main.transform;
		zoomCamera = Camera.main;
		initPos = cam.position;
    }

    // Update is called once per frame	
	void Update()
	{
		UISprite joystickSprite = GameObject.Find("joystickSprite").GetComponent<UISprite>();
		UISprite joystickRing = GameObject.Find("joystickRing").GetComponent<UISprite>();
		UIJoystick j = GameObject.Find("Joystick").GetComponent<UIJoystick>();
		
		if(SV.control) {
			j.visible = true;
			joystickSprite.enabled = true;
			joystickRing.enabled = true;
		}
		else {
			j.visible = false;
			joystickSprite.enabled = false;
			joystickRing.enabled = false;
		}
		
		//Debug.Log("CAM: " + cam.position + " Terrain: " + Terrain.activeTerrain.GetPosition());
	}
	
	void LateUpdate ()
	{
    	// Only if there are touches
    	if (Input.touches.Length == 1)
    	{
        	// Only work with the first touch
        	// and only if the touch moved since last update
        	if (Input.touches[0].phase == TouchPhase.Moved)
        	{
				if (!SV.control)
				{
	           		//position.x = 1 * Input.touches[0].deltaPosition.x * speed * Time.deltaTime;
    	       		//position.y = 1 * Input.touches[0].deltaPosition.y * speed * Time.deltaTime;
					
					float x = 0;
					float y = 0;
					
					float deltaPosX = Input.touches[0].deltaPosition.x;
					float deltaPosY = Input.touches[0].deltaPosition.y;
					
					// era 50 il valore di soglia

					if(Mathf.Abs(deltaPosX) > 50)
					{
						deltaPosX = 50 * Mathf.Sign(deltaPosX);
					}
					
					if(Mathf.Abs(deltaPosY) > 50)
					{
						deltaPosY = 50 * Mathf.Sign(deltaPosY);
					}

					if(Time.timeScale > 0)
					{
						if(Time.deltaTime > 1) {
							x = deltaPosX * speed * 0.8f / Time.timeScale;
							y = deltaPosY * speed * 0.8f / Time.timeScale;							
						}
						else {
							x = deltaPosX * speed * Time.deltaTime / Time.timeScale;
							y = deltaPosY * speed * Time.deltaTime / Time.timeScale;
						}
					}
					else {
	           			x = deltaPosX * speed * Time.deltaTime;
    	       			y = deltaPosY * speed * Time.deltaTime;						
					}
					
					if(DynamicCheckBounds(x, y))
					{
						position.x = x;
						position.y = y;
						
						cam.Translate(new Vector3(position.x, 0, position.y), Space.World); // vector * speed
					}

					/*
					if (CheckBounds())
					{
						cam.Translate(new Vector3(position.x, 0, position.y), Space.World); // vector * speed
					}
					*/
					
					Vector3 pos = cam.position;
            		pos.y -= (cam.position.y - initPos.y) * 0.1f;
            		//assign new position to camera position
            		cam.position = pos;
				}
        	}			
		}
		
		// Zoom
		if (Input.touchCount == 2  Input.GetTouch(0).phase == TouchPhase.Moved  Input.GetTouch(1).phase == TouchPhase.Moved) 
		{
			curDist = Input.GetTouch(0).position - Input.GetTouch(1).position; //current distance between finger touches
			prevDist = ((Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition) - (Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition)); //difference in previous locations using delta positions
			touchDelta = curDist.magnitude - prevDist.magnitude;
			speedTouch0 = Input.GetTouch(0).deltaPosition.magnitude / Input.GetTouch(0).deltaTime;
			speedTouch1 = Input.GetTouch(1).deltaPosition.magnitude / Input.GetTouch(1).deltaTime;
			
			if ((touchDelta + varianceInDistances <= 1)  (speedTouch0 > minPinchSpeed)  (speedTouch1 > minPinchSpeed))
			{
				zoomCamera.fieldOfView = Mathf.Clamp(zoomCamera.fieldOfView + (5 * speed),40,90);
			}

			if ((touchDelta + varianceInDistances > 1)  (speedTouch0 > minPinchSpeed)  (speedTouch1 > minPinchSpeed))
			{
				zoomCamera.fieldOfView = Mathf.Clamp(zoomCamera.fieldOfView - (5 * speed),40,90);
			}
			
		}
    }

    //this method casts a ray against world limit mask with length of 5 units and returns a boolean,
    //which indicates whether movement is possible in that direction
    //on hit: world limit reached - return false, no hit: free space - return true
    private bool CheckBounds()
    {
        Vector3 forw = transform.forward * position.y * -1;
        Vector3 side = transform.right * position.x * -1;

        if (Physics.Raycast(cam.position, forw, 10, SV.worldMask))
        {
            return false;
        }
        else if (Physics.Raycast(cam.position, side, 10, SV.worldMask))
		{
            return false;
		}

        return true;
    }
	
    private bool DynamicCheckBounds(float x, float y)
    {
        Vector3 forw = transform.forward * y * -1;
        Vector3 side = transform.right * x * -1;
		
        if (Physics.Raycast(cam.position, forw, 10, SV.worldMask))
        {
            return false;
        }
        else if (Physics.Raycast(cam.position, side, 10, SV.worldMask))
		{
            return false;
		}

        return true;
    }
	
}