# 6. Worked Example — Third-Person + Cinematic Cutaway Part of [[Cinemachine 3]]. Prev: [[5.Blends Custom Blends Cut vs Ease]]. Next: [[7.Pitfalls]]. **Goal:** A playable FreeLook third-person camera (`CM_Gameplay`) and a higher-priority cutaway (`CM_Cutaway`) that eases in on interact, with a light Impulse on impact. Input via [[Input System]]. Design framing from [[Level Up! (Review)]]. > **NOT compiled in Unity.** Verify against Cinemachine **3.1.x** and your Input System version. ## 6.1 Scene setup 1. Player capsule / character with a child empty `CameraTarget` at ~1.6m height. 2. **Main Camera** + **Cinemachine Brain**. Default Blend: Ease In Out, 0.5s. 3. Custom Blends asset: - `CM_Gameplay` → `CM_Cutaway` · Ease In Out · 0.6s - `CM_Cutaway` → `CM_Gameplay` · Ease Out · 0.4s 4. **GameObject → Cinemachine → FreeLook Camera** → rename `CM_Gameplay`. - Tracking Target = `CameraTarget` - Priority = 10 - Orbital Follow: Three Ring or Sphere; damp moderately - Input Axis Controller → bind Look (Vector2) from your `.inputactions` asset 5. Create second Cinemachine Camera `CM_Cutaway`: - Position Control: **Follow** or locked framing on an interactable - Rotation Control: **Hard Look At** or Rotation Composer on the point of interest - Priority = 0, **disabled** by default 6. Add **CinemachineImpulseListener** to `CM_Gameplay`. 7. On a heavy prop / landing volume: **CinemachineImpulseSource** (or Collision Impulse Source on feet). Folders: `Assets/_Project/Cinemachine/Cameras`, `Blends`, `Scripts`. ## 6.2 Camera director service ```csharp using System.Collections; using UnityEngine; using Unity.Cinemachine; /// <summary> /// Tiny camera "service" — see Architecture and Code Patterns. /// NOT compiled in Unity. /// </summary> public sealed class CameraDirector : MonoBehaviour { [SerializeField] CinemachineCamera gameplay; [SerializeField] CinemachineCamera cutaway; [SerializeField] int gameplayPriority = 10; [SerializeField] int cutawayPriority = 30; [SerializeField] float defaultHold = 2.5f; Coroutine _cutawayRoutine; void Awake() { if (gameplay != null) gameplay.Priority = gameplayPriority; if (cutaway != null) { cutaway.enabled = false; cutaway.Priority = 0; } } public void PlayCutaway(Transform lookAt, float holdSeconds = -1f) { if (cutaway == null) return; if (lookAt != null) cutaway.LookAt = lookAt; // confirm property in 3.1.x if (_cutawayRoutine != null) StopCoroutine(_cutawayRoutine); _cutawayRoutine = StartCoroutine(CutawayRoutine(holdSeconds < 0 ? defaultHold : holdSeconds)); } public void CancelCutaway() { if (_cutawayRoutine != null) StopCoroutine(_cutawayRoutine); _cutawayRoutine = null; RestoreGameplay(); } IEnumerator CutawayRoutine(float hold) { cutaway.enabled = true; cutaway.Priority = cutawayPriority; yield return new WaitForSeconds(hold); RestoreGameplay(); _cutawayRoutine = null; } void RestoreGameplay() { if (cutaway != null) { cutaway.Priority = 0; cutaway.enabled = false; } if (gameplay != null) gameplay.Priority = gameplayPriority; } } ``` ## 6.3 Interact trigger ```csharp using UnityEngine; using UnityEngine.InputSystem; /// <summary> /// Press Interact near a point of interest to run the cutaway. /// NOT compiled in Unity. /// </summary> public sealed class CutawayInteractable : MonoBehaviour { [SerializeField] CameraDirector director; [SerializeField] Transform framingTarget; [SerializeField] InputActionReference interact; [SerializeField] float range = 3f; [SerializeField] Transform player; void OnEnable() => interact?.action.Enable(); void OnDisable() => interact?.action.Disable(); void Update() { if (director == null || interact == null || player == null) return; if (!interact.action.WasPressedThisFrame()) return; if (Vector3.Distance(player.position, transform.position) > range) return; director.PlayCutaway(framingTarget != null ? framingTarget : transform); } } ``` ## 6.4 Landing Impulse ```csharp using UnityEngine; using Unity.Cinemachine; /// <summary> /// Call from a character landing check or Animation Event. /// NOT compiled in Unity. /// </summary> public sealed class LandingImpulse : MonoBehaviour { [SerializeField] CinemachineImpulseSource source; [SerializeField] float lightLand = 0.35f; [SerializeField] float hardLand = 1.0f; public void OnLanded(float impactSpeed) { if (source == null) return; float v = impactSpeed > 8f ? hardLand : lightLand; source.GenerateImpulse(v); } } ``` Hook `OnLanded` from movement code or an Animation Event on the land clip ([[Animation Advanced]]). ## 6.5 Optional Timeline beat For authored story cutaways, prefer a Timeline asset with a Cinemachine track ([[Timeline Basics]]) that activates `CM_Cutaway` (or dedicated shot cams) instead of the coroutine. Keep `CameraDirector` for *gameplay*-driven moments. ## 6.6 Checklist to Play-mode test 1. Look orbit works via Input Axis Controller. 2. Walk behind a thin wall — Deoccluder (if added) pulls camera forward without exploding into geometry. 3. Interact — Ease into cutaway, hold, Ease back. 4. Hard land — Impulse Listener shakes gameplay cam briefly. 5. No leftover Priority 30 cam after cancel. ## Unverified - `CinemachineCamera.LookAt` assignment API vs Tracking Target-only mode. - Exact Impulse `GenerateImpulse` overloads. - Input Action `WasPressedThisFrame` availability depends on your Input System package (see [[Input System]]).