Smooth 2D Camera Follow in Unity 6 with Cinemachine 3: Dead Zones, Confiners and Pixel-Perfect Snapping
A step-by-step Unity 6 tutorial for 2D camera follow with Cinemachine 3: dead zones, Confiner2D bounds, and pixel-perfect snapping that doesn't jitter.
Cinemachine 3 renamed so many components and menu items that most of the tutorials out there for it are really written for Cinemachine 2. If you’ve been hunting for “Framing Transposer” in Unity 6 and can’t find it anywhere, that’s why. This one builds a 2D follow camera from scratch in the current version, and covers the two things that go wrong most: the camera fighting your pixel snapping, and the camera happily following your player right off the edge of the map.
For what it’s worth, I’ve since switched my own JRPG to a 2.5D perspective camera (my advice after a few months of that: stick to 2D if you can). When I first started, though, I had a 2D camera and got pixel snapping wrong. My 32x32 sprites shimmered at the edges every time the player walked diagonally. That’s the bug this article is here to help you skip.
What you’ll have at the end
A camera that follows a 2D player with a dead zone (so it doesn’t twitch on every tiny movement), stays inside your level’s boundaries, and plays nicely with pixel snapping so your pixel art doesn’t shimmer. You’ll also know how to tune the damping so it feels responsive instead of floaty, and where to go next for room transitions and screen shake.
Engine, package versions and prerequisites
This targets Unity 6000.0 LTS, with:
- Cinemachine 3.1, installed from Package Manager (Unity Registry)
- A Pixel Perfect Camera for pixel art. If your project uses URP (the Universal 2D template), it’s already built in. On the Built-in Render Pipeline, install the free 2D Pixel Perfect package (
com.unity.2d.pixel-perfect) instead.
You’ll need a 2D scene with a player you can move (a Rigidbody2D and a movement script, or the tilemap-based movement from my grid-based movement tutorial works fine too), and a Tilemap or sprite-based level with clear edges. If your sprites are already imported with a Pixels Per Unit setting you’re happy with, keep that number handy for step 6. If you’re not sure what PPU does to your art, this explainer covers it.
Step 1: Check which Cinemachine version you have
Open Window > Package Manager, click Cinemachine under “In Project” (or install it from Unity Registry if it’s missing), and check the version number at the top right.
This matters because the two major versions don’t use the same names. Cinemachine 2.x uses CinemachineVirtualCamera, created from GameObject > Cinemachine > Virtual Camera. Cinemachine 3.x, which this article uses, renamed it to CinemachineCamera, created from GameObject > Cinemachine > Cinemachine Camera. Another quick tell: in 3.x the camera’s Inspector says Position Control where 2.x said Body. If your menus don’t match what’s below, you’re probably on 2.x and need a different tutorial.
Step 2: Add a Cinemachine Camera and point it at the player
- GameObject > Cinemachine > Cinemachine Camera to add one to the scene.
- Cinemachine adds a
CinemachineBrainto your Main Camera on its own if it doesn’t already have one. The brain is the piece that takes what your Cinemachine cameras decide and moves the real camera, so leave it there. - Select the new Cinemachine Camera and drag your player into the Tracking Target field.
If you press Play now and the camera doesn’t follow, check Position Control on the Cinemachine Camera. While it’s set to None, the camera has a target but no instructions for following it, which is exactly what the next step sets up.
Step 3: Pick a Position Control (Position Composer vs. Hard Lock to Target)
On the Cinemachine Camera, find the Position Control dropdown. For a 2D follow camera you’ll mostly pick between two:
- Position Composer: smooths and frames the target using a dead zone and damping. This is the one you want for a standard side-scroller or top-down follow camera.
- Hard Lock to Target: the camera matches the target’s position exactly, every frame, with no smoothing.
Hard Lock sounds worse, but it isn’t always. If your player moves tile by tile, like in the grid-based movement tutorial, a smoothed camera can look like it’s dragging half a step behind that snappy movement. Hard Lock keeps the camera glued to the player and feels tighter for that kind of game. For anything with continuous movement (a Rigidbody2D walking around, a platformer, most JRPG overworlds), go with Position Composer.
Set Position Control to Position Composer for the rest of this tutorial.
Step 4: Add a dead zone so small movements don’t drag the camera
With Position Composer selected, open Composition and find Dead Zone. Its Size is a width and height measured as a fraction of the screen, where 1 is the whole screen.
The dead zone is the area in the middle of the frame where the player can move without the camera reacting at all. Without one, tiny movements (idle sway, a small hop, a controller stick that isn’t perfectly centered) turn into a camera that never quite sits still. With one, the player can wander a bit and the camera only catches up once they leave that area.
Start around 0.1 to 0.2 for both and adjust by eye. Too small and you’re back to constant little adjustments. Too big and the player gets uncomfortably close to the edge of the screen before the camera moves at all.
Step 5: Stop the camera leaving the level with a Confiner2D and a PolygonCollider2D
Right now nothing stops the camera from following the player past the edge of your level into empty gray space. CinemachineConfiner2D fixes that.
- Create an empty GameObject called
LevelBounds. - Add a
PolygonCollider2Dto it, tick Is Trigger (it doesn’t need to physically block anything), and edit its points in the Scene view to trace the outer edge of your playable area. - On your Cinemachine Camera, click Add Extension > CinemachineConfiner2D.
- Drag the
LevelBoundsobject’sPolygonCollider2Dinto the Bounding Shape 2D field.
The confiner keeps the camera’s view inside that polygon, so it never shows anything past it. It has its own Damping setting too, but that one only smooths the camera around corners so it doesn’t jump. It isn’t a second layer of follow smoothing, so keep it low unless you see the camera snap at a corner.
One gotcha worth knowing before you hit it: if you change that polygon at runtime (resizing a level, moving walls), the confiner has already cached the shape and won’t notice on its own. Unity’s own advice is to avoid reshaping it where you can. Giving each area its own Cinemachine Camera with its own bounds and blending between them is much cheaper (more on that at the end). If you do need to reshape it, tell the confiner:
using UnityEngine;
using Unity.Cinemachine;
public class LevelBoundsUpdater : MonoBehaviour
{
[SerializeField] private CinemachineConfiner2D confiner;
public void OnLevelBoundsChanged()
{
// Call this any time the PolygonCollider2D's points change at runtime,
// otherwise the confiner keeps using its cached, now-stale shape.
confiner.InvalidateBoundingShapeCache();
}
}
While you’re testing in the editor, the confiner’s Inspector has an Invalidate Bounding Shape Cache button that does the same thing.
Step 6: Make it work with pixel art
This is the step that bit me. Everything above works fine for a game without pixel art, but pixel art needs a couple more pieces or your sprites will shimmer at the edges, especially when moving diagonally.
- Add a Pixel Perfect Camera to your Main Camera (the one with the
CinemachineBrain, not the Cinemachine Camera). On URP it’s built in; on the Built-in Render Pipeline it comes from the 2D Pixel Perfect package. - Set Asset Pixels Per Unit to the PPU your sprites were imported with. Not sure what that should be? That’s what the Pixels Per Unit article is for.
- Set Reference Resolution to your game’s target resolution.
- Turn on pixel snapping. On URP it’s the Pixel Snapping option under Grid Snapping; with the Built-in package it’s a Pixel Snapping checkbox.
- On your Cinemachine Camera, click Add Extension > CinemachinePixelPerfect.
Why both? The Pixel Perfect Camera and Cinemachine each want to control the camera’s orthographic size, and without that extension they fight over it. The extension lets Cinemachine use the size the Pixel Perfect Camera works out.
Pixel snapping is what fixes the shimmer. Cinemachine still moves the camera smoothly, which is the whole point of the damping and dead zone. Pixel snapping stops the sprites themselves from sitting between pixels, so they move in whole-pixel steps. Diagonal movement is where you notice it most, because the player is between pixels on both axes at once. One caveat from Unity’s docs: if you use Upscale Render Texture instead of pixel snapping, Cinemachine’s framing can come out slightly off.
If sprites still stutter while the camera moves and your player uses a Rigidbody2D, set that Rigidbody2D’s Interpolate to Interpolate, and make sure the CinemachineBrain’s Update Method is Smart Update (Unity’s recommended setting). Physics moves the player on a fixed timestep while the screen redraws every frame, and without interpolation the two drift in and out of step, which looks like jitter.
Step 7: Tune the damping without making the camera feel floaty
Back on the Position Composer, Damping sets how quickly the camera catches up once the player leaves the dead zone. Bigger numbers mean a slower, smoother catch-up. Smaller numbers mean a snappier one.
If the camera feels floaty, the usual suspects are damping set too high, or a dead zone so big that the camera starts moving late and then has to hurry to catch up. Values around 0.2 to 0.5 are a reasonable starting point for a normal top-down or side-view game, and anything with dashes or sprints usually wants lower. The confiner’s damping isn’t the cause here, since it only kicks in around corners.
Common pitfalls
- The camera doesn’t follow at all. Position Control is still set to None, or there’s no
CinemachineBrainon the camera taggedMainCamera(easy to lose if you delete and replace the Main Camera). Pick a Position Control, and add aCinemachineBrainback if it’s missing. - The camera stops following and sits in one spot. Your
PolygonCollider2Dis smaller than the camera’s view at its current orthographic size, so there’s nowhere inside the bounds for the confiner to put it. Make the polygon bigger than the camera’s frame, not just bigger than the level art. - The camera ignores walls you moved at runtime. The confiner is still using its cached shape. Call
InvalidateBoundingShapeCache()after the change, or better, use a separate camera for each area. - Sprite edges shimmer, mostly on diagonals. Pixel snapping is off, Asset Pixels Per Unit doesn’t match your sprite import settings, or the CinemachinePixelPerfect extension is missing.
- Sprites stutter while the camera moves. Usually a
Rigidbody2Dwithout interpolation. See the end of step 6. - Hitches when the confiner rebuilds its bounds. A polygon traced around every jagged tile edge makes that rebuild heavier than it needs to be. A simple rectangle, or a loose outline of the playable area, is enough. It doesn’t have to hug every tile.
Where to go next: room-to-room camera swaps, screen shake, look-ahead on fast movement
Once this is working, a few natural next steps:
- Room-to-room camera swaps. Give each room its own Cinemachine Camera with its own confiner bounds, and use trigger volumes to raise the Priority of whichever room the player walks into. Cinemachine blends between them for you, and it’s also what Unity recommends over reshaping one confiner at runtime. The same trick works for cutting to a separate battle camera, if your game has a combat screen like the one in my JRPG combat devlog.
- Screen shake with Cinemachine’s Impulse system: a
CinemachineImpulseSourceon whatever causes the shake, and aCinemachineImpulseListeneron the camera. Tuning the shake takes some fiddling, so it’s worth reading up on before you wire it in. - Lookahead for fast movement. The Position Composer’s Lookahead Time and Lookahead Smoothing nudge the framing ahead of a fast-moving player instead of centering on them. For anything with a dash or sprint, try it before deciding the camera itself is the problem.
Registration card
Register to receive one focused post every weekday — engine tutorials, marketing tactics, and design craft. Free, unsubscribe anytime.
No spam. We never share your address. No purchase necessary — it's free.