Tags: unity, camera, cinemachine, follow, damping, orthographic, perspective, shake, game-dev Last updated: 2026-06-27

Camera Systems Cheatsheet

Quick Reference

ApproachBest ForComplexity
Scripted FollowSimple 2D/3D follow cameraLow
CinemachineProduction-quality cinematic camerasLow–Medium
Multi-cameraCutscenes, camera switchingMedium
Custom PhysicsSmooth damping, collision avoidanceMedium

Scripted Follow Camera

Smooth Follow (3D)

public Transform target;
public Vector3 offset = new(0, 5, -10);
public float smoothSpeed = 5f;

void LateUpdate() {
    Vector3 targetPos = target.position + offset;
    transform.position = Vector3.Lerp(
        transform.position, targetPos, smoothSpeed * Time.deltaTime);
    transform.LookAt(target);
}

2D Follow with Dead Zone

public Vector2 deadZone = new(1f, 0.5f);
public float smoothTime = 0.3f;
Vector3 velocity;

void LateUpdate() {
    Vector3 delta = target.position - transform.position;
    delta.z = 0;

    if (Mathf.Abs(delta.x) > deadZone.x)
        delta.x -= Mathf.Sign(delta.x) * deadZone.x;
    else delta.x = 0;

    if (Mathf.Abs(delta.y) > deadZone.y)
        delta.y -= Mathf.Sign(delta.y) * deadZone.y;
    else delta.y = 0;

    transform.position = Vector3.SmoothDamp(
        transform.position, transform.position + delta,
        ref velocity, smoothTime);
}

Camera Bounds (Clamp to Level)

public Vector2 minBounds, maxBounds;
public float camHalfHeight, camHalfWidth;

void LateUpdate() {
    Vector3 pos = target.position + offset;
    pos.x = Mathf.Clamp(pos.x, minBounds.x + camHalfWidth,
                               maxBounds.x - camHalfWidth);
    pos.y = Mathf.Clamp(pos.y, minBounds.y + camHalfHeight,
                               maxBounds.y - camHalfHeight);
    transform.position = pos;
}

Cinemachine

Virtual Camera Types

CameraUse Case
Virtual CameraBase camera with composer/lookat/follow
FreeLookOrbital camera around target
Blend ListSequenced camera cuts
State-DrivenSwitches per Animator state
ClearShotAuto-picks best view avoiding obstacles
DollyTrack-based movement
2D CameraOrthographic 2D follow

Follow & LookAt

CinemachineVirtualCamera vcam;
vcam.Follow = playerTransform;
vcam.LookAt = playerTransform;

var transposer = vcam.GetCinemachineComponent<CinemachineTransposer>();
transposer.m_FollowOffset = new Vector3(0, 5, -10);

var composer = vcam.GetCinemachineComponent<CinemachineComposer>();
composer.m_TrackedObjectOffset = Vector3.up * 1.5f;

Damping & Dead Zone

PropertyDescription
X/Y/Z DampingSmoothing per axis (0 = instant)
Dead Zone Width/HeightNo movement within zone
Soft Zone Width/HeightGradual movement beyond dead zone
BiasHow much to favour centre (0–1)
Lookahead TimeAnticipate movement direction
Lookahead SmoothingHow quickly lookahead adjusts

Camera Shake (Cinemachine Impulse)

# Generate impulse
CinemachineImpulseManager.Instance.GenerateImpulse(
    transform.position, direction, 0.5f, 0.2f);

CinemachineImpulseSource source = GetComponent<CinemachineImpulseSource>();
source.GenerateImpulse(direction * force);

# Listener on VCam
CinemachineImpulseListener listener;
listener.m_Gain = 1f;
listener.m_ChannelMask = ~0;

Camera Shake (Scripted)

public IEnumerator Shake(float duration, float magnitude) {
    Vector3 originalPos = transform.localPosition;
    float elapsed = 0f;

    while (elapsed < duration) {
        float x = Random.Range(-1f, 1f) * magnitude;
        float y = Random.Range(-1f, 1f) * magnitude;
        transform.localPosition = originalPos + new Vector3(x, y, 0);
        elapsed += Time.deltaTime;
        yield return null;
    }
    transform.localPosition = originalPos;
}

Shake Presets

TypeDurationMagnitude
Gunshot0.05s0.3
Explosion0.3s2.0
Footstep0.1s0.1
Earthquake2.0s1.5
Hit reaction0.15s0.5

Orthographic vs Perspective

AspectOrthographicPerspective
Depth perceptionNoneRealistic
Size consistencyObjects same size regardless of distanceFarther = smaller
Use case2D, isometric, strategy3D, FPS, TPS
ZoomAdjust orthographic sizeAdjust FOV or move camera
Camera cam = GetComponent<Camera>();
cam.orthographic = true;
cam.orthographicSize = 5f;

cam.orthographic = false;
cam.fieldOfView = 60f;

Multi-Camera Setup

public Camera[] cameras;
int currentIndex = 0;

void SwitchCamera(int index) {
    foreach (Camera cam in cameras) cam.enabled = false;
    cameras[index].enabled = true;
    currentIndex = index;
}

IEnumerator Cutscene() {
    SwitchCamera(1); yield return new WaitForSeconds(3f);
    SwitchCamera(2); yield return new WaitForSeconds(5f);
    SwitchCamera(0);
}

Cinemachine Blend

CinemachineBrain brain = Camera.main.GetComponent<CinemachineBrain>();
brain.m_DefaultBlend.m_Style = CinemachineBlendDefinition.Style.EaseInOut;
brain.m_DefaultBlend.m_Time = 1.5f;