How to prevent camera from being behind objects

Hello,:slight_smile:

I make a 3rd person game with a simple camera movement (child to the player, that’s it) but if I rotate the player near a wall the camera goes behind it and the player is not visible

I want the camera to move closer to the player if something like this has happened.

I have searched a lot to find a good script and I have found this —v The problem is that it has a lot of other functions too. What should I change so it has only the camera collision effect?

using UnityEngine;
    using System.Collections;
     
    public class WowCamera : MonoBehaviour
    {
     
        public Transform target;
       
        public float targetHeight = 1.7f;
        public float distance = 5.0f;
     
        public float maxDistance = 20;
        public float minDistance = .6f;
     
        public float xSpeed = 250.0f;
        public float ySpeed = 120.0f;
     
        public int yMinLimit = -80;
        public int yMaxLimit = 80;
     
        public int zoomRate = 40;
     
        public float rotationDampening = 3.0f;
        public float zoomDampening = 5.0f;
     
        private float x = 0.0f;
        private float y = 0.0f;
        private float currentDistance;
        private float desiredDistance;
        private float correctedDistance;
     
        void Start ()
        {
            Vector3 angles = transform.eulerAngles;
            x = angles.x;
            y = angles.y;
     
            currentDistance = distance;
            desiredDistance = distance;
            correctedDistance = distance;
     
            // Make the rigid body not change rotation
            if (rigidbody)
                rigidbody.freezeRotation = true;
        }
       
        /**
         * Camera logic on LateUpdate to only update after all character movement logic has been handled.
         */
        void LateUpdate ()
        {
            // Don't do anything if target is not defined
            if (!target)
                return;
     
          	//If either mouse buttons are down, let the mouse govern camera position
		if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
		{
			x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
			y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
		 }
					            
		// otherwise, ease behind the target if any of the directional keys are pressed
		else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
		 {
			float targetRotationAngle = target.eulerAngles.y;
			float currentRotationAngle = transform.eulerAngles.y;
			 x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
		}

            y = ClampAngle(y, yMinLimit, yMaxLimit);
     
            // set camera rotation
            Quaternion rotation = Quaternion.Euler(y, x, 0);
     
            // calculate the desired distance
            desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
            desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
            correctedDistance = desiredDistance;
     
            // calculate desired camera position
            Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
     
            // check for collision using the true target's desired registration point as set by user using height
            RaycastHit collisionHit;
            Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
     
            // if there was a collision, correct the camera position and calculate the corrected distance
            bool isCorrected = false;
            if (Physics.Linecast(trueTargetPosition, position, out collisionHit))
            {
                position = collisionHit.point;
                correctedDistance = Vector3.Distance(trueTargetPosition, position);
                isCorrected = true;
            }
           
            // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
            currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
     
            // recalculate position based on the new currentDistance
            position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));
     
            transform.rotation = rotation;
            transform.position = position;
        }
     
        private static float ClampAngle(float angle, float min, float max)
        {
            if (angle < -360)
                angle += 360;
            if (angle > 360)
                angle -= 360;
            return Mathf.Clamp(angle, min, max);
        }
    }

I am not sure I understand your request, also you only have 1 function inside this script which is ClampAngle.

I don’t mean the coding term of “function” but the English word. I want to say that the script does many things, like rotating the camera with the mouse and stuff. I only need the part that makes the camera not to pass through walls and objects.

Ok, then I would suggest creating another script to do exactly that. If you find you are writing a script that has multiple functionality that doesn’t really need to be in the same place, creating separate scripts for each is a good idea. It allows you to create modular code which can be used on other projects. So if you only wanted the functionality of the camera not passing through walls etc, you can just add that script!

That’s what I want to do, but I don’t know what parts of this script to use!

Ok…weird :smile: did you not write the functionality for it?

Anyway, all you need in the base functionality of having a non clipping camera is to cast a ray from the camera to the player(like you have done). If the ray returns a hit other than the player, change it’s position to be the position of that hit (plus any extra needed distance for thick walls).

Pretty much you need the following.

// calculate desired camera position

            Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));

     

            // check for collision using the true target's desired registration point as set by user using height

            RaycastHit collisionHit;

            Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);

     

            // if there was a collision, correct the camera position and calculate the corrected distance

            bool isCorrected = false;

            if (Physics.Linecast(trueTargetPosition, position, out collisionHit))

            {

                position = collisionHit.point;

                correctedDistance = Vector3.Distance(trueTargetPosition, position);

                isCorrected = true;

            }

           

            // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance

            currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;

     

            // recalculate position based on the new currentDistance

            position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));


            transform.position = position;

No, I didn’t write this script, I found it on a forum thread.

Can you implement this to a script please, because I’m not sure what to do exactly… :slight_smile:

Uhm, no thanks. I told you exactly what you need. I will even give you steps.

  1. Create a new script
  2. Have a variable that is linked to the player gameObject ( camera target)
  3. Cast a ray from the target(the player) to the camera.
  4. If that ray hit’s something that is not the camera, store the hit location in a variable
  5. Set the cameras new position to be the hit location of the ray. ( use smoothing functions like lerp to make it move slowly if you want)