| Engine | Unity 2022.3 LTS or newer |
|---|---|
| Language | C# |
| Attach to | Main Camera (Orthographic) |
| Time to run | ~3 minutes |
| Level | Beginner |
| Output | One file (~60 lines) |
| Dependencies | None. No Cinemachine. |
The prompt
Open a fresh chat at claude.ai/new, paste, and send.
$ Build me a Unity 2022.3+ 2D smooth camera follow as a single C# MonoBehaviour. // shape - Single file, CameraFollow.cs, attached to an Orthographic camera. - Public/[SerializeField] Transform target for the player. - No Cinemachine, no packages. // follow - Follow in LateUpdate, not Update. - Use Vector3.SmoothDamp with a stored velocity ref field. - [SerializeField] float smoothTime, default 0.15. - Preserve the camera's own z (do not copy the target's z). - [SerializeField] Vector2 offset, default zero. // deadzone - A [SerializeField] Vector2 deadzone (width, height) in world units, default (1, 0.6). - Only move the camera on an axis once the target leaves the deadzone box centered on the camera. Small movements inside the box do not move the camera. // bounds (optional) - [SerializeField] bool useBounds. - [SerializeField] Vector2 minBounds, maxBounds. - When useBounds is true, clamp the final camera position so the visible area never shows past min/max. Account for the orthographic half-height and half-width (camera.orthographicSize and aspect). // constraints - No magic numbers. Everything tunable is SerializeField. - Guard against a null target (return early, no NullReferenceException spam). // return format - One file. No prose before or after the code. - Brief comments only on the deadzone math and the bounds clamp, since those are the non-obvious bits.
What this gets you
A camera that feels like a camera. It trails the player with a soft SmoothDamp instead of locking rigidly to them, ignores the little sub-pixel wobble that makes locked cameras look nervous, and never reveals the grey nothing past the edge of your tilemap.
It is one script with everything exposed in the inspector, so tuning "tight action-game camera" versus "loose exploration camera" is a slider, not a rewrite.
Why it matters
SmoothDamp over Lerp
A raw Lerp with a fixed t never actually arrives and its speed depends on frame rate. SmoothDamp is built for exactly this: it eases toward a target with a time constant you set in seconds, framerate independent. It is the right tool and most homemade cameras use the wrong one.
The deadzone
Without a deadzone the camera reacts to every tiny movement, including idle animation sway, and the whole screen jitters. A deadzone box lets the player move a little without dragging the world, which reads as calm and intentional.
Bounds that account for zoom
Clamping the camera to min/max is easy to get wrong: if you clamp the camera center you still show past the edge by half a screen. The clamp has to subtract the orthographic half-width and half-height, which depend on orthographicSize and aspect. This prompt calls that out so Claude does the math.
What good output looks like
- Follow logic is in LateUpdate. If it is in Update or FixedUpdate, expect jitter or lag. Move it to LateUpdate.
- A single velocity ref field for SmoothDamp. Vector3.SmoothDamp needs a
ref Vector3that persists between frames. It should be a private field, not a local that gets reset every frame (which would kill the smoothing). - Camera keeps its own z. The final position should reuse
transform.position.z, not the target's z. Copying the target z (usually 0) puts the camera in the scene plane and everything vanishes. - Bounds clamp uses orthographicSize and aspect. Look for
cam.orthographicSizeand* cam.aspectin the clamp. If the clamp uses raw min/max with no half-extent, you will still see past the edges.
How to wire it up
- Save the output as
CameraFollow.cs. - Select your Main Camera, make sure Projection is set to Orthographic.
- Attach the script, then drag the player GameObject into the
targetfield. - Press Play. The camera should trail the player smoothly and ignore small movements inside the deadzone.
- If you want level edges respected, tick
useBoundsand set min/max to your level corners in world units.
Common gotchas
Everything disappears when I press Play
The camera z got overwritten with the target's z (0). The final position must keep the camera's original z, usually -10 for 2D. Check that the script preserves transform.position.z.
The camera still shows past the level edge
The bounds clamp is clamping the camera center, not the visible area. It needs to subtract the orthographic half-height (orthographicSize) and half-width (orthographicSize * aspect) before clamping.
The follow is jerky
Either it is running in Update instead of LateUpdate, or the SmoothDamp velocity is a local variable being reset each frame. It has to be a persistent field passed by ref.
Where to go next
- Look-ahead. Offset the target point in the direction the player is moving so you see more of where you are going.
- Screen shake. Add a temporary random offset on hit, decaying over time, applied on top of the follow position.
- Pixel-perfect snap. Round the final position to the pixel grid. See the pixel-perfect camera writeup for the why, the same idea ports to Unity.
Use it however you want
The prompt is CC0, paste it, modify it, ship a game with it. The output Claude gives you is yours. A link back to pixeldex.dev in your project's README helps the next solo dev find this stuff.