Коротко. Камера за персонажем в Unity 2D — это скрипт на Main Camera, который в LateUpdate() переносит камеру к герою: transform.position = Vector3.SmoothDamp(transform.position, target.position + offset, ref velocity, smoothTime);. Если камера дёргается, включите у Rigidbody2D героя Interpolate. Без кода то же самое делает пакет Cinemachine: 2D Camera, Position Composer и Confiner 2D.
Ниже: готовый скрипт с границами уровня под Unity 6.6, замеры дрожания и отставания камеры и пошаговая настройка Cinemachine 3.
Камера — первое, что замечает игрок. Если она отстаёт, дёргается или показывает пустоту за краем уровня, игра сразу выглядит недоделанной. Чтобы не гадать, почему так бывает, мы собрали уровень в Unity 6.6 (6000.6) и измерили, как ведут себя разные варианты камеры на 30, 60 и 144 кадрах в секунду. Цифры ниже взяты из этого теста, а весь код компилируется в этой версии без предупреждений.
Тест пригодился сразу. Первая версия нашего скрипта ограничивала центр камеры жёсткими числами, и в широком окне Game кадр вышел за левый край уровня на 1,13 единицы. На мониторе другой ширины граница сдвинулась бы иначе. В итоговом скрипте этой ошибки нет: он сам считает ширину кадра.
Как работает камера, которая следует за персонажем
Камера в Unity — обычный объект сцены, поэтому «следовать» значит каждый кадр менять её transform.position. Самый простой вариант — одна строка в LateUpdate():
transform.position = target.position + offset;
Здесь offset — сдвиг относительно героя. По оси Z он должен быть −10: камера стоит перед спрайтами, а при Z = 0 она окажется в их плоскости, и экран станет пустым. Такая камера жёстко прилипает к герою и повторяет каждое его движение. Обычно хочется мягче, поэтому дальше добавим плавность.
Шаг 1. Скрипт плавной камеры
Создайте скрипт CameraFollow2D, повесьте его на Main Camera и перетащите героя в поле Target. Плавность даёт Vector3.SmoothDamp: он мягко разгоняет и тормозит камеру, а параметр smoothTime — это примерное время в секундах, за которое камера догоняет героя.
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class CameraFollow2D : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private Vector3 offset = new Vector3(0f, 1f, -10f);
[SerializeField] private float smoothTime = 0.2f;
[Header("Края уровня")]
[SerializeField] private bool useBounds = true;
[SerializeField] private Vector2 levelMin = new Vector2(-12f, -6f);
[SerializeField] private Vector2 levelMax = new Vector2(32f, 9f);
private Camera cam;
private Vector3 velocity;
private void Awake()
{
cam = GetComponent<Camera>();
}
// LateUpdate: к этому моменту персонаж уже сдвинулся в этом кадре
private void LateUpdate()
{
if (target == null) return;
Vector3 desired = target.position + offset;
Vector3 pos = Vector3.SmoothDamp(transform.position, desired, ref velocity, smoothTime);
if (useBounds)
{
// Половина видимой области: высоту задаёт Size, ширина зависит от экрана
float halfHeight = cam.orthographicSize;
float halfWidth = halfHeight * cam.aspect;
pos.x = Mathf.Clamp(pos.x, levelMin.x + halfWidth, levelMax.x - halfWidth);
pos.y = Mathf.Clamp(pos.y, levelMin.y + halfHeight, levelMax.y - halfHeight);
}
transform.position = pos;
}
// Жёлтая рамка в окне Scene: края уровня, за которые камера не заглянет
private void OnDrawGizmosSelected()
{
if (!useBounds) return;
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube((levelMin + levelMax) / 2f, levelMax - levelMin);
}
}
Почему LateUpdate(), а не Update(): Unity вызывает его после всех Update() в кадре. К этому моменту герой уже сдвинулся, и камера едет к его новой позиции, а не к позиции прошлого кадра. Так советует и документация Unity для камер, следующих за объектом.
Lerp или SmoothDamp
Во многих уроках камеру сглаживают так: Vector3.Lerp(transform.position, target, 5f * Time.deltaTime). Это работает, но результат сильнее зависит от FPS. Мы гоняли героя со скоростью 6 м/с и мерили, насколько камера отстаёт от него при разной частоте кадров:
| Частота кадров | Lerp × Time.deltaTime | SmoothDamp (0,2 с) |
|---|---|---|
| 30 FPS | 1,00 | 1,10 |
| 60 FPS | 1,10 | 1,15 |
| 144 FPS | 1,16 | 1,18 |
| Разброс | 16% | 7% |
Отставание указано в единицах Unity. С Lerp камера на слабом компьютере держится к герою заметно ближе, чем на быстром, и ощущение от управления меняется. SmoothDamp стабильнее, а его настройку легче понять: это время в секундах.
Шаг 2. Почему камера дёргается и как это исправить
Главная причина дрожания — не скрипт камеры, а герой. Rigidbody2D двигается в физическом шаге, 50 раз в секунду, а кадров на экране больше. Без интерполяции в одних кадрах герой стоит на месте, в других прыгает сразу на целый шаг физики. Мы проверили это на 144 FPS, герой двигался со скоростью 6 м/с:
| Interpolate у героя | Камера | Неравномерность хода камеры | Дрожание героя на экране |
|---|---|---|---|
| None | жёстко за героем | 138% | 0 px |
| None | SmoothDamp | 0,5% | 6,2 px |
| Interpolate | жёстко за героем | 0% | 0 px |
| Interpolate | SmoothDamp | 0% | 0 px |
Без интерполяции дёргается что-то одно: либо весь мир (камера едет рывками), либо сам герой (камера едет плавно, а он прыгает по экрану на 6 пикселей при Full HD). Лекарство одно — галочка в инспекторе героя:
Если всё ещё дёргается: проверьте, что героя с Rigidbody2D не двигают через transform.position, только через linearVelocity или силы. И что камерой управляет кто-то один: скрипт и Cinemachine одновременно будут спорить за её позицию. Как правильно двигать героя, разобрано в статье про движение и прыжок в Unity 2D.
Шаг 3. Границы уровня, чтобы камера не показывала пустоту
Без ограничений камера у края уровня покажет то, что за стеной: пустой фон или недостроенные куски сцены. Поэтому в скрипте есть поля Level Min и Level Max — левый нижний и правый верхний угол уровня. Центр камеры нельзя подпускать к краю вплотную: от края нужно отступить на половину кадра.
- Половина высоты кадра — это Size ортографической камеры (
cam.orthographicSize). - Половина ширины — Size, умноженный на соотношение сторон экрана (
cam.aspect). Поэтому ширину нельзя вписать числом заранее: на экранах 16:9 и 21:9 она разная.
С этой поправкой в нашем тесте левый край кадра остановился ровно на краю уровня, на отметке −12,00, при любой ширине окна Game.
Шаг 4. Камера через Cinemachine 3
Cinemachine — официальный пакет Unity для управления камерой без кода. Всё, что мы написали выше, в нём уже есть, и даже больше: мёртвая зона, взгляд вперёд, плавные переходы между камерами. Мы проверяли на версии 3.1.7.
- Откройте Window → Package Management → Package Manager, во вкладке Unity Registry найдите Cinemachine и нажмите Install.
- Создайте камеру через GameObject → Cinemachine → Targeted Cameras → 2D Camera. Unity сам добавит на Main Camera компонент Cinemachine Brain: теперь главная камера слушается Cinemachine. Скрипт
CameraFollow2Dс неё уберите. - Перетащите героя в поле Tracking Target. В нашем тесте меню его не заполнило, даже когда герой был выделен.
- В поле Lens задайте размер кадра — аналог Size у обычной камеры.
За следование отвечает компонент Cinemachine Position Composer. Три настройки, которые стоит знать:
- Damping — задержка по X и Y, аналог
smoothTime. Мы поставили 1 по горизонтали и 0,5 по вертикали: камера мягко догоняет на бегу и быстрее реагирует на прыжки. - Dead Zone — область в центре экрана, внутри которой герой ходит, а камера стоит. Убирает мелкое покачивание, когда игрок топчется на месте.
- Target Offset — сдвиг точки, за которой следит камера. С Y = 1 над героем видно больше неба и платформ.
Границы уровня в Cinemachine задаёт расширение Confiner 2D. Создайте пустой объект CameraBounds, добавьте ему Polygon Collider 2D с галочкой Is Trigger и растяните фигуру по краям уровня. Затем у Cinemachine Camera в списке Add Extension выберите Cinemachine Confiner 2D и перетащите CameraBounds в поле Bounding Shape 2D.
Галочка Is Trigger нужна, чтобы рамка камеры не стала стеной для героя: о том, чем триггер отличается от обычного коллайдера, мы подробно писали в статье про физику, коллайдеры и триггеры. В тесте Confiner 2D остановил левый край кадра на −12,00, ровно как наш скрипт.
Скрипт или Cinemachine: что выбрать
| Свой скрипт | Cinemachine | |
|---|---|---|
| Установка | ничего не нужно | пакет из Package Manager |
| Плавность и границы | пишете сами | Damping и Confiner 2D |
| Мёртвая зона, взгляд вперёд | ещё код | галочка в инспекторе |
| Понимание, как всё устроено | полное | после первого скрипта |
Наш совет: один раз напишите камеру скриптом, чтобы понять принцип, а в настоящих проектах берите Cinemachine. Когда камера и герой готовы, следующий шаг — переход между уровнями.
Вывод
Плавная камера в 2D — это SmoothDamp в LateUpdate(), края уровня с поправкой на размер кадра и Interpolate у Rigidbody2D героя. Последняя галочка решает большинство жалоб «камера дёргается». В Cinemachine то же самое собирается из Position Composer и Confiner 2D без единой строки кода.
Если вы только начинаете, загляните в основы C# для Unity: там разобраны SerializeField и GetComponent из этого скрипта. Собрать из этих механик целую игру с проверкой заданий можно на бесплатном курсе Unity Старт и дальше по полной программе.
Частые вопросы
Как сделать, чтобы камера следовала за персонажем в Unity 2D?
Повесьте на Main Camera скрипт, который в LateUpdate ставит камеру в позицию героя со сдвигом: transform.position = target.position + offset. Сдвиг по Z должен быть -10, иначе камера окажется в плоскости спрайтов. Для плавности используйте Vector3.SmoothDamp или Cinemachine.
Почему камера дёргается при движении персонажа?
Чаще всего у Rigidbody2D героя не включена интерполяция. Физика считается 50 раз в секунду, а кадров на экране больше, и без Interpolate герой движется рывками. Поставьте у Rigidbody2D Interpolate: Interpolate, а камеру двигайте в LateUpdate.
Что лучше для камеры: Lerp или SmoothDamp?
Для камеры лучше Vector3.SmoothDamp: он плавно разгоняется и тормозит, а плавность задаётся в секундах. Популярный вариант Lerp(pos, target, speed * Time.deltaTime) зависит от FPS сильнее: в нашем тесте отставание камеры менялось на 16% между 30 и 144 кадрами, у SmoothDamp на 7%.
Как ограничить камеру границами уровня?
Ограничьте центр камеры через Mathf.Clamp, отступив от краёв уровня на половину видимой области: по высоте это Orthographic Size, по ширине Size, умноженный на camera.aspect. В Cinemachine то же делает расширение Confiner 2D с Polygon Collider 2D по краям уровня.
Что такое Cinemachine и нужен ли он новичку?
Cinemachine — официальный пакет Unity для управления камерой без кода. В нём уже есть плавное следование, мёртвая зона и ограничение границами уровня. Новичку стоит один раз написать камеру скриптом, чтобы понять принцип, а в проектах использовать Cinemachine.


