Complete camera collision detection (Third person games)

Well, I don’t know what to say. I’m pretty excited because after DAYS of coding this camera script, I finally have it working properly. No more wall clipping and I love it. I know a lot of other people are in need of a dynamic camera so it’s only right that I share this script. lol

    [Header("Camera Properties")]
    public float DistanceAway;                     //how far the camera is from the player.
    public float DistanceUp;                    //how high the camera is above the player
    public float smooth = 4.0f;                    //how smooth the camera moves into place
    public float rotateAround = 70f;            //the angle at which you will rotate the camera (on an axis)
    [Header("Player to follow")]
    public Transform target;                    //the target the camera follows
    [Header("Layer(s) to include")]
    public LayerMask CamOcclusion;                //the layers that will be affected by collision
    [Header("Map coordinate script")]
    public worldVectorMap wvm;
    RaycastHit hit;
    float cameraHeight = 55f;
    float cameraPan = 0f;
    float camRotateSpeed = 180f;
    Vector3 camPosition;
    Vector3 camMask;
    Vector3 followMask;
    // Use this for initialization
    void Start () {
        //the statement below automatically positions the camera behind the target.
        rotateAround = target.eulerAngles.y - 45f;
    }
    void Update(){

    }
    // Update is called once per frame

    void LateUpdate () {
        //Offset of the targets transform (Since the pivot point is usually at the feet).
        Vector3 targetOffset = new Vector3(target.position.x, (target.position.y + 2f), target.position.z);
        Quaternion rotation = Quaternion.Euler(cameraHeight, rotateAround, cameraPan);
        Vector3 vectorMask = Vector3.one;
        Vector3 rotateVector = rotation * vectorMask;
        //this determines where both the camera and it's mask will be.
        //the camMask is for forcing the camera to push away from walls.
        camPosition = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;
        camMask = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;

        occludeRay(ref targetOffset);
        smoothCamMethod();

        transform.LookAt(target);

        #region wrap the cam orbit rotation
        if(rotateAround > 360){
            rotateAround = 0f;
        }
        else if(rotateAround < 0f){
            rotateAround = (rotateAround + 360f);
        }
        #endregion

        rotateAround += customPreferences.HorizontalAxis2 * camRotateSpeed * Time.deltaTime;
        DistanceUp = Mathf.Clamp(DistanceUp += customPreferences.VerticalAxis2, -0.79f, 2.3f);
    }
    void smoothCamMethod(){
        smooth = 4f;
        transform.position = Vector3.Lerp (transform.position, camPosition, Time.deltaTime * smooth);
    }
    void occludeRay(ref Vector3 targetFollow){
        #region prevent wall clipping
        //declare a new raycast hit.
        RaycastHit wallHit = new RaycastHit();
        //linecast from your player (targetFollow) to your cameras mask (camMask) to find collisions.
        if(Physics.Linecast(targetFollow, camMask, out wallHit, CamOcclusion)){
            //the smooth is increased so you detect geometry collisions faster.
            smooth = 10f;
            //the x and z coordinates are pushed away from the wall by hit.normal.
            //the y coordinate stays the same.
            camPosition = new Vector3(wallHit.point.x + wallHit.normal.x * 0.5f, camPosition.y, wallHit.point.z + wallHit.normal.z * 0.5f);
        }
        #endregion
    }
}

Here’s an additional video of how it looks in action

6 Likes

Nice! Maybe post it in Showcase instead?

Swimming with a sword out looks super dangerous.

Oh, and great job, this looks really good :slight_smile:

Wow

Hey,
cool script :stuck_out_tongue:
But it gives me Error on worldVectorMap and on customPreferences

Kind Regard StonedLover

1 Like

Hey It’s super cool, but I’m having troubles with the custom preferences. Is there another script that I need or something?

2 Likes

It’s missing worldVectorMap and customPreferences… I have no idea what they are. This is heavily incomplete code.

1 Like

Here’s the working code:

using UnityEngine;
using System.Collections;

public class RealCamera : MonoBehaviour{
  
    [Header("Camera Properties")]
    private float DistanceAway;                     //how far the camera is from the player.

    public float minDistance = 1;                //min camera distance
    public float maxDistance = 2;                //max camera distance

    public float DistanceUp = -2;                    //how high the camera is above the player
    public float smooth = 4.0f;                    //how smooth the camera moves into place
    public float rotateAround = 70f;            //the angle at which you will rotate the camera (on an axis)

    [Header("Player to follow")]
    public Transform target;                    //the target the camera follows

    [Header("Layer(s) to include")]
    public LayerMask CamOcclusion;                //the layers that will be affected by collision

    [Header("Map coordinate script")]
//    public worldVectorMap wvm;
    RaycastHit hit;
    float cameraHeight = 55f;
    float cameraPan = 0f;
    float camRotateSpeed = 180f;
    Vector3 camPosition;
    Vector3 camMask;
    Vector3 followMask;

    private float HorizontalAxis;
    private float VerticalAxis;

    // Use this for initialization
    void Start(){
        //the statement below automatically positions the camera behind the target.
        rotateAround = target.eulerAngles.y - 45f;


    }

    void LateUpdate(){

        HorizontalAxis = Input.GetAxis("Horizontal");
        VerticalAxis = Input.GetAxis("Vertical");

        //Offset of the targets transform (Since the pivot point is usually at the feet).
        Vector3 targetOffset = new Vector3(target.position.x, (target.position.y + 2f), target.position.z);
        Quaternion rotation = Quaternion.Euler(cameraHeight, rotateAround, cameraPan);
        Vector3 vectorMask = Vector3.one;
        Vector3 rotateVector = rotation * vectorMask;
        //this determines where both the camera and it's mask will be.
        //the camMask is for forcing the camera to push away from walls.
        camPosition = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;
        camMask = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;

        occludeRay(ref targetOffset);
        smoothCamMethod();

        transform.LookAt(target);

        #region wrap the cam orbit rotation
        if(rotateAround > 360){
            rotateAround = 0f;
        }
        else if(rotateAround < 0f){
            rotateAround = (rotateAround + 360f);
        }
        #endregion

        rotateAround += HorizontalAxis * camRotateSpeed * Time.deltaTime;
        //DistanceUp = Mathf.Clamp(DistanceUp += VerticalAxis, -0.79f, 2.3f);
        DistanceAway = Mathf.Clamp(DistanceAway += VerticalAxis, minDistance, maxDistance);

    }
    void smoothCamMethod(){
      
        smooth = 4f;
        transform.position = Vector3.Lerp (transform.position, camPosition, Time.deltaTime * smooth);
    }
    void occludeRay(ref Vector3 targetFollow){
        #region prevent wall clipping
        //declare a new raycast hit.
        RaycastHit wallHit = new RaycastHit();
        //linecast from your player (targetFollow) to your cameras mask (camMask) to find collisions.
        if(Physics.Linecast(targetFollow, camMask, out wallHit, CamOcclusion)){
            //the smooth is increased so you detect geometry collisions faster.
            smooth = 10f;
            //the x and z coordinates are pushed away from the wall by hit.normal.
            //the y coordinate stays the same.
            camPosition = new Vector3(wallHit.point.x + wallHit.normal.x * 0.5f, camPosition.y, wallHit.point.z + wallHit.normal.z * 0.5f);
        }
        #endregion
    }
}
11 Likes

wow that’s really smooth. if u want credit i’ll give it. that’s the best camera script I’ve seen in unity

not working properly at all :frowning:
the camera follows the player from above (bird look)

1 Like

Genius. I had hard time detecting collision with Terrain. Tried plenty of different approaches, including Colliders!! This is just brilliant.

It works but it’s disturbing my controls

Excelent script dude! thanks

Thank you this script is awesome!