Third-Person Camera in Unity 3D

Third-Person Camera in Unity 3D

by NSDG • Sep 21, 2019 • 0 Comments
335

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 a 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 = 4.5f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    public Transform playerCameraParent;
    public float lookSpeed = 2.0f;
    public float lookXLimit = 30.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 / lookSpeed;
    }

    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");
            rotation.x += -Input.GetAxis("Mouse Y");
            rotation.x = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit);
            transform.eulerAngles = new Vector2(0, rotation.y) * lookSpeed;
            playerCameraParent.localRotation = Quaternion.Euler(rotation.x * lookSpeed, 0, 0);
        }
    }
}
  • 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: Creating a 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 if there is anything in between. That way it will prevent the Camera from clipping through 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.