First Person Camera
First person mouse look camera with sensitivity, vertical clamp, and cursor lock. Plug into any FPS or exploration game.
How to Use
Create your Player object with a child Camera
Attach FirstPersonCamera to the Camera
Adjust mouse sensitivity and vertical clamp angles
Cursor locks automatically on Start
Press Escape to toggle cursor lock
Pair with 3D Player Controller for complete FPS movement
Features
- Smooth mouse look with SmoothDamp for configurable input smoothing
- Vertical angle clamping to prevent over-rotation
- Automatic cursor lock on start with Escape toggle
- Separate horizontal (player body) and vertical (camera) rotation
- AddRecoil method for weapon kickback integration
- Pauses rotation when cursor is unlocked for menu interaction
When to Use This
Essential for any first-person game — FPS shooters, horror games, walking simulators, and exploration titles. Use this when you need standard mouse-look controls on a camera that is a child of the player object. The AddRecoil method makes it especially suited for FPS games with weapon systems.
Common Mistakes
The camera must be a child of the player GameObject — the script uses transform.parent to find the player body for horizontal rotation. If the camera is not parented correctly, horizontal rotation won't work. Setting smoothing too low makes the camera feel sluggish, while too high makes it jittery. The minVerticalAngle and maxVerticalAngle are in degrees, not radians.
Source Code
using UnityEngine;
/// <summary>
/// First person mouse look camera. Attach to the Camera (child of player).
/// Handles horizontal rotation on the player body and vertical rotation on the camera.
/// </summary>
public class FirstPersonCamera : MonoBehaviour
{
[Header("Sensitivity")]
[SerializeField] private float mouseSensitivity = 2f;
[SerializeField] private float smoothing = 1.5f;
[Header("Vertical Clamp")]
[SerializeField] private float minVerticalAngle = -90f;
[SerializeField] private float maxVerticalAngle = 90f;
[Header("Cursor")]
[SerializeField] private bool lockCursorOnStart = true;
private Transform playerBody;
private float xRotation;
private float yRotation;
private Vector2 currentMouseDelta;
private Vector2 currentMouseDeltaVelocity;
private void Awake()
{
playerBody = transform.parent;
}
private void Start()
{
if (lockCursorOnStart)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
bool locked = Cursor.lockState == CursorLockMode.Locked;
Cursor.lockState = locked ? CursorLockMode.None : CursorLockMode.Locked;
Cursor.visible = locked;
}
if (Cursor.lockState != CursorLockMode.Locked) return;
Vector2 targetMouseDelta = new Vector2(
Input.GetAxisRaw("Mouse X"),
Input.GetAxisRaw("Mouse Y")
);
currentMouseDelta = Vector2.SmoothDamp(
currentMouseDelta, targetMouseDelta,
ref currentMouseDeltaVelocity, 1f / smoothing
);
xRotation -= currentMouseDelta.y * mouseSensitivity;
xRotation = Mathf.Clamp(xRotation, minVerticalAngle, maxVerticalAngle);
yRotation += currentMouseDelta.x * mouseSensitivity;
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
if (playerBody != null)
playerBody.rotation = Quaternion.Euler(0f, yRotation, 0f);
}
/// <summary>
/// Add recoil to the camera (e.g., from weapon fire).
/// </summary>
public void AddRecoil(float vertical, float horizontal)
{
xRotation -= vertical;
yRotation += horizontal;
}
}