Third Person Camera
Orbit camera with collision detection, zoom, and vertical angle limits. Ideal for action-adventure and RPG games.
How to Use
1
Create an empty CameraRig object and parent your Camera to it
2
Attach ThirdPersonCamera to the CameraRig
3
Assign your player Transform as the Target
4
Adjust distance, zoom range, and rotation speed
5
Set collision layers to avoid clipping through walls
6
Camera auto-avoids obstacles via SphereCast
Source Code
C#
using UnityEngine;
/// <summary>
/// Third person orbit camera with collision avoidance.
/// Attach to an empty CameraRig object, parent your Camera as a child.
/// </summary>
public class ThirdPersonCamera : MonoBehaviour
{
[Header("Target")]
[SerializeField] private Transform target;
[SerializeField] private Vector3 targetOffset = new Vector3(0f, 1.5f, 0f);
[Header("Orbit")]
[SerializeField] private float rotationSpeed = 5f;
[SerializeField] private float minVerticalAngle = -30f;
[SerializeField] private float maxVerticalAngle = 70f;
[Header("Distance")]
[SerializeField] private float defaultDistance = 5f;
[SerializeField] private float minDistance = 1.5f;
[SerializeField] private float maxDistance = 15f;
[SerializeField] private float zoomSpeed = 3f;
[SerializeField] private float zoomSmoothing = 8f;
[Header("Collision")]
[SerializeField] private float collisionRadius = 0.3f;
[SerializeField] private LayerMask collisionLayers = ~0;
[Header("Smoothing")]
[SerializeField] private float followSmoothing = 10f;
private float currentX;
private float currentY = 15f;
private float currentDistance;
private float targetDistance;
private Camera cam;
private void Awake()
{
cam = GetComponentInChildren<Camera>();
currentDistance = defaultDistance;
targetDistance = defaultDistance;
}
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void LateUpdate()
{
if (target == null) return;
HandleInput();
UpdatePosition();
}
private void HandleInput()
{
if (Cursor.lockState != CursorLockMode.Locked) return;
currentX += Input.GetAxis("Mouse X") * rotationSpeed;
currentY -= Input.GetAxis("Mouse Y") * rotationSpeed;
currentY = Mathf.Clamp(currentY, minVerticalAngle, maxVerticalAngle);
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scroll) > 0.01f)
{
targetDistance -= scroll * zoomSpeed;
targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);
}
}
private void UpdatePosition()
{
currentDistance = Mathf.Lerp(currentDistance, targetDistance, Time.deltaTime * zoomSmoothing);
Vector3 focusPoint = target.position + targetOffset;
Quaternion rotation = Quaternion.Euler(currentY, currentX, 0f);
Vector3 desiredPosition = focusPoint + rotation * new Vector3(0f, 0f, -currentDistance);
// Collision check
float adjustedDistance = currentDistance;
Vector3 direction = desiredPosition - focusPoint;
if (Physics.SphereCast(focusPoint, collisionRadius, direction.normalized,
out RaycastHit hit, currentDistance, collisionLayers))
{
adjustedDistance = hit.distance - collisionRadius;
adjustedDistance = Mathf.Max(adjustedDistance, minDistance * 0.5f);
}
Vector3 finalPosition = focusPoint + rotation * new Vector3(0f, 0f, -adjustedDistance);
transform.position = Vector3.Lerp(transform.position, finalPosition, Time.deltaTime * followSmoothing);
transform.LookAt(focusPoint);
}
/// <summary>
/// Set a new target to follow at runtime.
/// </summary>
public void SetTarget(Transform newTarget)
{
target = newTarget;
}
}