Developing Game in Unity? Check Template Projects, Tools, VFX & many more!

Third-Person Camera in Unity 3D

14536

In this tutorial I will be showing how to create a Third-Person Camera movement with collision detection in Unity 3D.

So let's begin!

Step 1: Creating Player controller

First we will create a simple Player controller:

  • Create a new Game Object (Game Object -> Create Empty) and name it "Player"
  • Create new Capsule (Game Object -> 3D Object -> Capsule) and move it inside "Player" Object
  • Remove Capsule Collider component from Capsule and change its position to (0, 1, 0)
  • Create new GameObject and name it "CameraParent" and move it inside "Player" Object, change its position to (0, 1.64, 0)
  • Move the Main Camera inside "CameraParent" Object and move it behind the Player (In my case I moved it to this position: (0.5, 0.6, -2.9))

Third Person Camera in Unity

  • Create new Script and call it SC_TPSController and paste the code below inside it:

SC_TPSController.cs

using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class SC_TPSController : MonoBehaviour
{
    public float speed = 7.5f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    public Transform playerCameraParent;
    public float lookSpeed = 2.0f;
    public float lookXLimit = 60.0f;

    CharacterController characterController;
    Vector3 moveDirection = Vector3.zero;
    Vector2 rotation = Vector2.zero;

    [HideInInspector]
    public bool canMove = true;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        rotation.y = transform.eulerAngles.y;
    }

    void Update()
    {
        if (characterController.isGrounded)
        {
            // We are grounded, so recalculate move direction based on axes
            Vector3 forward = transform.TransformDirection(Vector3.forward);
            Vector3 right = transform.TransformDirection(Vector3.right);
            float curSpeedX = canMove ? speed * Input.GetAxis("Vertical") : 0;
            float curSpeedY = canMove ? speed * Input.GetAxis("Horizontal") : 0;
            moveDirection = (forward * curSpeedX) + (right * curSpeedY);

            if (Input.GetButton("Jump") && canMove)
            {
                moveDirection.y = jumpSpeed;
            }
        }

        // Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
        // when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
        // as an acceleration (ms^-2)
        moveDirection.y -= gravity * Time.deltaTime;

        // Move the controller
        characterController.Move(moveDirection * Time.deltaTime);

        // Player and Camera rotation
        if (canMove)
        {
            rotation.y += Input.GetAxis("Mouse X") * lookSpeed;
            rotation.x += -Input.GetAxis("Mouse Y") * lookSpeed;
            rotation.x = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit);
            playerCameraParent.localRotation = Quaternion.Euler(rotation.x, 0, 0);
            transform.eulerAngles = new Vector2(0, rotation.y);
        }
    }
}
  • Attach SC_TPSController script to "Player" Object (You will notice that it also added another component called Character Controller, change its center value to (0, 1, 0))
  • Assign "CameraParent" Object to playerCameraParent variable

Step 2: Adding Camera collision detection

Camera collision detection will consist of a script that will check if there is anything between the Camera and the Player, and will automatically move the Camera closer, thus preventing the Camera from clipping through the objects.

  • Create new script, name it SC_CameraCollision then paste the code below inside it:

SC_CameraCollision.cs

using UnityEngine;

public class SC_CameraCollision : MonoBehaviour
{
    public Transform referenceTransform;
    public float collisionOffset = 0.2f; //To prevent Camera from clipping through Objects

    Vector3 defaultPos;
    Vector3 directionNormalized;
    Transform parentTransform;
    float defaultDistance;

    // Start is called before the first frame update
    void Start()
    {
        defaultPos =  transform.localPosition;
        directionNormalized = defaultPos.normalized;
        parentTransform = transform.parent;
        defaultDistance = Vector3.Distance(defaultPos, Vector3.zero);
    }

    // FixedUpdate for physics calculations
    void FixedUpdate()
    {
        Vector3 currentPos = defaultPos;
        RaycastHit hit;
        Vector3 dirTmp = parentTransform.TransformPoint(defaultPos) - referenceTransform.position;
        if (Physics.SphereCast(referenceTransform.position,  collisionOffset, dirTmp, out hit, defaultDistance))
        {
            currentPos = (directionNormalized * (hit.distance - collisionOffset));
        }

        transform.localPosition = Vector3.Lerp(transform.localPosition, currentPos, Time.deltaTime * 15f);
    }
}
  • Attach SC_CameraCollision to Main Camera
  • Assign CameraParent to Reference Transform variable

The TPS Camera is now ready, press Play to test it.