Limit Camera With Raycast

I have a basic script that moves the camera, as well as limits the camera to a certain distance, but I wonder how you would limit it to a raycasts hit distance? I have the raycast and the hit distance working out, but I don’t know why I’m drawing a blank here, I must’ve been working too hard haha.

Here is my script,

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

public class CameraControls : MonoBehaviour
{
    public float speed, normalSpeed,fastSpeed;
    public bool isFast;
    public float cameraDistanceMax;
    public float cameraDistanceMin;
    public float cameraDistance;
    public float scrollSpeed = 1f;
    // Start is called before the first frame update
    void Start()
    {
        fastSpeed = normalSpeed * 2;
    }

    private void Update()
    {
        Ray ray = new Ray(transform.position, Vector3.down);
        Debug.DrawRay(transform.position, Vector3.down * 100, Color.blue);
        RaycastHit hit;
        Physics.Raycast(ray, out hit);
         if(hit.distance< cameraDistanceMin)
        {
            cameraDistance = cameraDistanceMin + hit.distance;
        }
        print(hit.distance);
    }
    void LateUpdate()
    {
        Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
        Vector3 direction = input.normalized;
        Vector3 velocity = direction * speed;
        Vector3 moveAmount = velocity * Time.deltaTime;

        transform.position += moveAmount;
        if (Input.GetKey(KeyCode.LeftShift)) {
            isFast = true;
        }
      
        else
        {
            isFast = false;
        }
        if(isFast == true)
        {
            speed = fastSpeed;
        }
        else
        {
            speed = normalSpeed;
        }
        cameraDistance += Input.GetAxis("Mouse ScrollWheel") * (scrollSpeed * -1);
        cameraDistance = Mathf.Clamp(cameraDistance, cameraDistanceMin, cameraDistanceMax);
        transform.position = new Vector3(transform.position.x, cameraDistance, transform.position.z);
    }
}

I basically just want it to clamp the camera distance based on the raycasts distance, rather than the predefined min/max. How would I go about doing this? As in, have a min max for the raycast’s distance instead, and if the raycast’s distance is too close or too far, limit the movement.

Thanks in advance.

You can set the camera’s farClipPlane to whatever you want. This will give you some fairly screwy looking results, though, unless you’re okay with your skybox showing up for anything that’s too far away.

Your idea also sounds like it will just look really weird in general. As the center of the screen encounters nearby obstacles, everything beyond that obstacle disappears? And if the center of the screen happens to be looking at something far away, everything more close-by is visible?

It’s a top down simulation game, the camera only ever faces down. I want it to move up or down with the terrain and obstacles, I will make the raycast ignore certain things.like birds and whatnot lol. I have the camera limited to -60 min and 50 max, but I’d like to have a more permanent solution.

I’m just curious why you actually need to do this. Do you perceive this to be a performance improvement to limit camera draw distance? Given that you say it’s top-down, that doesn’t seem likely. Or is your world extremely tall, so there’s tons of stuff straight down you don’t want the player to see until they descend?

Not the draw distance, the camera game object. Sorry I didn’t specify, by distance, I mean the distance the camera is able to move up or down, min is the closest to the ground, max is the highest. I want the min to be limited when the ray’s distance is say, 15, and set the max to 100 or so, rather than a preset minimum camera distance.

Sorry, I guess I misread this part:

I guess the language of “limiting” the camera “distance” convinced me this was related to draw distance. Sorry about that.

In that case, you always want the camera a certain distance above the ground? If so, using your raycasting, a RaycastHit has a “point” field, which tells you the position where the raycast hit the ground (or hit whatever it hit). You could use that as the base position, and then add whatever you want to it, and use that to decide the camera’s position. So, if the hit “point” was (24, 3.5, 9), you could take the “3.5” y-value, add something to it, and make that your camera’s y-value.

I’d probably recommend you add a bit of code for smoothly adjusting the camera’s height based on that new value being a target value rather than immediately changing the y-value, to avoid really dramatic jumps up/down.

1 Like

Oh, it’s okay haha.

Well, I got the distance from the raycast working, I’m just unsure of the implementation. I basically want it to limit the camera based on the raycasts distance, rather than the preset

cameraDistance = Mathf.Clamp(cameraDistance, cameraDistanceMin, cameraDistanceMax);
        transform.position = new Vector3(transform.position.x, cameraDistance, transform.position.z);

So, I want to change this min and max distances to correlate with the raycast, rather than the camera’s position… So, this min and max, I want to set to 15 and 100 or so, I’ll probably play with it later, and have it clamp the camera’s position based on the rays distance.

And yeah, I’ll add some smoothing, I’m just trying to get the system worked out first :stuck_out_tongue:

By Min and Max distances, you mean the player controls (maybe with the scroll wheel) the zoom level of how zoomed in or zoomed out the camera is? So they can move the camera up and down, but only within the min/max range? And you keep saying “camera distance”. Just to confirm, does that mean the camera’s “distance” from the ground?

In any case, it seems like all you need is to take the RaycastHit.point.y + 15 for the min allowed value, and RaycastHit.point.y + 100 for the max allowed value, then force the camera to stay within that range. As the camera moves over the uneven ground, the min/max allowed y-values will move up and down with the ground’s height.

1 Like

That worked, thank you very much! I changed the clamp to

 cameraDistance = Mathf.Clamp(cameraDistance, hit.point.y + cameraDistanceMin, hit.point.y + cameraDistanceMax);

So I can change the min and max in the inspector :slight_smile:

1 Like