U
tab 03Camera & Input6 lessons — tap to open
02 / 06 · 10 min
Camera & Input

Third-person orbit

your project so far

Assets/

Scenes/

Arena.unity

CameraTarget

Scripts/

PlayerMovement.csFollowCamera.cs→OrbitCamera.cs

you already havethis lesson addsthis lesson retires

Step two. FollowCamera watches from a fixed angle — you can never look behind the Knight. Remove it from Main Camera and put this on instead.

A third-person camera is a camera on the end of a stick. The stick is anchored on the character; the mouse rotates it.

animated diagram

Mouse X spins the stick horizontally (yaw), mouse Y raises and lowers it (pitch).

The orbit rig

OrbitCamera.cs
using UnityEngine;

public class OrbitCamera : MonoBehaviour
{
    [SerializeField] private Transform target;          // the Knight's CameraTarget child, from tab 02
    [SerializeField] private float distance = 6f;
    [SerializeField] private float sensitivity = 240f;
    [SerializeField] private float minPitch = -25f;
    [SerializeField] private float maxPitch = 65f;
    [SerializeField] private LayerMask obstacles;

    private float yaw;
    private float pitch = 20f;

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;       // hide and centre the cursor
        Cursor.visible = false;
    }

    void LateUpdate()
    {
        // ---- 1. accumulate the angles
        yaw   += Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
        pitch -= Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
        pitch  = Mathf.Clamp(pitch, minPitch, maxPitch);   // never flip over

        // ---- 2. build the rotation, then push back along -Z
        Quaternion rot = Quaternion.Euler(pitch, yaw, 0f);
        Vector3 pivot = target.position;
        Vector3 wanted = pivot + rot * new Vector3(0f, 0f, -distance);

        // ---- 3. pull in if a wall is in the way
        float realDistance = distance;
        if (Physics.SphereCast(pivot, 0.3f, (wanted - pivot).normalized,
                               out RaycastHit hit, distance, obstacles))
            realDistance = hit.distance - 0.2f;

        transform.position = pivot + rot * new Vector3(0f, 0f, -realDistance);
        transform.rotation = rot;
    }

    public float Yaw => yaw;   // movement uses this to know 'forward'
}
  • pitch -= mouseY because in Unity a positive pitch tilts the camera down. Subtracting gives the standard 'push forward = look up' feel.

  • Clamping pitch is not optional. Without it the camera passes over the head and the world turns upside down.

  • rot * new Vector3(0, 0, -distance) is the whole trick: rotate a backwards vector, and you get the camera position.

Wire it into movement

Your PlayerMovement already reads Camera.main.transform.eulerAngles.y, so this camera works with it immediately — moving forward now means away from this camera.

Mouse sensitivity that does not lie

  1. 1

    Mouse X/Y are already per-frame deltas, so multiplying by Time.deltaTime is technically wrong — but it makes the Inspector number stable across frame rates. Pick one convention and keep it.

  2. 2

    Expose sensitivity in a settings menu. Every player has a different mouse DPI.

  3. 3

    Add an Invert Y toggle. Roughly one player in five needs it, and they will bounce off your game without it.

C# script
if (Input.GetKeyDown(KeyCode.Escape))
{
    Cursor.lockState = CursorLockMode.None;
    Cursor.visible = true;
}

Common mistakes

  • Storing yaw and pitch in transform.eulerAngles and reading them back breaks the clamp: Unity wraps the angles to 0–360, so pitch reads 350 instead of -10. Keep the two angles in your own float fields.

  • A second camera tagged MainCamera, added for a menu or by Cinemachine, makes Camera.main return whichever it finds first, and forward flips. Keep one MainCamera tag, or read Yaw from this script instead.

  • obstacles left at Nothing means the SphereCast never hits and the camera still clips through walls; set it to the level geometry layer. Never include the Player layer, or the camera hides behind the character itself.