Cinemachine на практике: камера, которая не вызывает желания выключить игру
Камера в игре — одна из самых неблагодарных задач. Сделал нормально — никто не заметит. Сделал плохо — игроки закроют игру через пять минут, не понимая, почему «как-то некомфортно». Cinemachine — пакет, который превратил три прежних кошмара (следование за персонажем, переходы, катсцены) в нечто конфигурируемое в инспекторе. Расскажу, как я её использую, какие настройки экономят дни, и где она ломается.
Опираюсь на Unity 6 (6000.x), Cinemachine 3.x. В CM 3 поменялся API относительно CM 2 — туториалы из 2021 года могут вводить в заблуждение.
Что такое Cinemachine и зачем
Cinemachine — это система виртуальных камер. Вместо одной Main Camera, которую ты двигаешь скриптом, у тебя десяток CM Camera — каждая со своими правилами слежения, и одна реальная камера, которую Cinemachine Brain переключает между ними.
Главная идея: вместо «программирую движение камеры» ты «настраиваю поведение в инспекторе». Дизайнер может править параметры, не дёргая программиста.
Что Cinemachine даёт из коробки:
- Follow + Look At с разными алгоритмами (Hard Follow, Smooth, Damping, Framing).
- Гладкие переходы между виртуальными камерами (Cut, Ease In/Out, Custom Blend).
- Confiner — ограничение зоны движения камеры коллайдером.
- Collider — отталкивание камеры от препятствий.
- Impulse Source — единая система камера-шейков.
- Splines, dolly tracks для проездов.
- 3rd Person, Free Look, Top Down — preset'ы под жанры.
Базовое: Cinemachine Brain + одна виртуальная камера
Минимальная сетка:
- На Main Camera — компонент CinemachineBrain.
- Создать CinemachineCamera в сцене (правый клик в иерархии).
- Указать в ней Tracking Target = transform персонажа.
- В компонентах CM Camera выбрать CinemachinePosition = Follow и CinemachineRotation = Composer.
Camera следует за персонажем с заданным offset'ом, плавно поворачивается на цель. По умолчанию параметры мягкие, без особой возни — уже работает.
Когда несколько CM Camera, активной считается с наивысшим Priority. CM Brain переключается на ту, у которой priority выше. Это позволяет делать переходы (катсцена → возврат) без скриптов:
_cutsceneCamera.Priority = 20; // включаем катсцену
// ...
_cutsceneCamera.Priority = 0; // возвращаемся к main
Tracking: Hard Follow vs Smooth vs Framing
В компоненте CinemachinePosition выбираешь алгоритм:
Hard Follow
Камера жёстко привязана к offset'у от target'а. Никакого сглаживания. Подходит для топ-даун игр или строгих фиксированных видов.
Smooth Follow
С damping'ом — камера догоняет цель. Параметры X Damping, Y Damping, Z Damping. Чем выше — тем мягче, но тем больше задержка.
Для платформера типичные значения: X=0.5, Y=0.3, Z=1.0. Для шутера от третьего лица — X=0.1, Y=0.1, Z=0.5 (быстрее реагирует).
Framing Transposer / Position Composer
Самый умный режим. Указываешь, в какой части экрана должен быть target (например, по центру по горизонтали и в нижней трети по вертикали для платформера). Камера двигается так, чтобы target оставался в этой зоне.
Дополнительные параметры:
- Dead Zone Width/Height — зона, в которой target может двигаться без движения камеры. Для платформера маленький, для open-world — больше.
- Soft Zone Width/Height — зона мягкого реагирования.
- Lookahead Time — камера предсказывает движение target'а. Для платформера 0.3–0.5, чтобы видеть, куда бежишь.
Я почти всегда использую Framing/Position Composer. Lookahead делает камеру «умной» бесплатно.
Look At: Composer и Group Composer
Аналогично есть Rotation: Hard Look At, Composer, Group Composer.
Composer
Цель удерживается в указанной части экрана. Хорошо для шутеров от третьего лица — герой в нижнем-левом, простор для прицела по правой части экрана.
Group Composer
Несколько объектов как target. Камера сама подбирает расстояние и угол, чтобы все были в кадре. Используется в файтингах и кооп-играх.
var group = gameObject.AddComponent<CinemachineTargetGroup>();
group.AddMember(player1.transform, weight: 1f, radius: 1f);
group.AddMember(player2.transform, weight: 1f, radius: 1f);
_cmCamera.LookAt = group.transform;
Collider: камера и стены
Очень полезный компонент, который часто забывают добавить. CinemachineCollider (или Camera Decollider в CM 3) проверяет, не упёрлась ли камера в препятствие, и сдвигает её ближе к цели.
Параметры:
- Avoid Obstacles — обнаружение коллизии.
- Distance Limit — насколько близко может подойти к цели.
- Damping When Occluded — скорость возврата на дистанцию после очистки обзора.
На 3D-проектах без Collider'а камера регулярно «уезжает» внутрь стен, и пользователю плохо видно героя. Collider закрывает 90% таких сценариев.
Импульсы: камера-шейк, не нужен скрипт
Камера-shake без Cinemachine — это собственный compute через AnimationCurve, скрипт на каждой пушке, ручная синхронизация. С CM Impulse — две настройки.
На источнике взрыва/выстрела добавляешь CinemachineImpulseSource. Настраиваешь форму волны (Bump, Recoil, Rumble) и амплитуду. В коде:
[SerializeField] private CinemachineImpulseSource _explosionImpulse;
private void Explode()
{
_explosionImpulse.GenerateImpulse();
}
На CM Camera — компонент CinemachineImpulseListener. Он подхватывает все импульсы в зоне и применяет к камере. Один раз настроил — все взрывы автоматом трясут картинку.
Можно ограничить ImpulseSource радиусом: дальние взрывы не трясут камеру так сильно, как близкие. Реалистично и без ручной возни.
Confiner: камера в границах уровня
В платформерах и top-down играх часто нужно ограничить зону камеры — чтобы она не показывала «за пределами уровня». CinemachineConfiner2D (для 2D) или CinemachineConfiner3D делают это через Polygon Collider.
Создаёшь GameObject с PolygonCollider2D, рисуешь форму уровня, передаёшь его в Confiner на CM Camera. Камера будет двигаться только внутри полигона.
На больших уровнях с разными зонами — несколько Confiner'ов на разные CM Camera, переключаешь по триггеру входа в зону. Boss-арена сужает обзор, обычная зона — широкая.
Cinemachine + Timeline: катсцены без боли
Catscene workflow в CM:
- В Window → Sequencing → Timeline создаёшь Timeline asset.
- В нём — Cinemachine Track.
- На track перетаскиваешь несколько CM Camera, формируя последовательность shot'ов.
- Между ними — переходы (cross-fade'ы или жёсткие cut'ы).
- В коде запускаешь PlayableDirector.
На том же Timeline — анимации, аудио, активация/деактивация объектов. Получается полноценный cutscene-инструмент, и режиссёр может сидеть в Unity и править кадр за кадром.
Совет: каждая CM Camera для cutscene — отдельная нода в иерархии, с понятными именами (CamShot01_Hero_Closeup, CamShot02_Wide). Через год будешь спасаться.
Free Look: 3rd person camera
Самый частый паттерн в action-играх — orbit-камера, которая ходит вокруг героя по сфере, реагируя на мышь/стик.
CinemachineFreeLook делает это из коробки. Три rig'а (Top, Middle, Bottom) — камера интерполирует между ними по вертикальному вводу. Каждый rig — это orbit с радиусом и высотой.
Настройки, которые матчат:
- X Axis: input от мыши/правого стика, скорость поворота. Обычно 300–500 для мыши, 250 для геймпада.
- Y Axis: тангаж. Лимиты обычно от 0.1 до 0.9 (избежать пол и потолок).
- Recenter to Target: автоматический поворот за движением героя. Полезно для adventure-игр, не нужно для шутеров.
- Common Lens: одно поле зрения для всех rig'ов. Иначе при переходе между top/bottom у тебя зум скачет.
Когда Cinemachine — не лучший выбор
- VR. Камеру в VR двигать нельзя (по крайней мере, не по yaw'у — игрок укачается). Cinemachine для VR подходит ограниченно: только для cutscene, и желательно с явным fade'ом.
- Top-down strategy. Тут проще написать ручное движение по WASD/мыши, чем настраивать CM Free Pan.
- 2D платформер с очень специфичной логикой (квадратные shot'ы как в Celeste). CM работает, но нужно фактически написать кастомный extension.
Расширения: пишем свои Behaviour
В CM есть extensibility через CinemachineExtension. Свой компонент, который изменяет поведение камеры. Пример: камера, которая немного отдаляется при низком HP игрока, чтобы показать угрозу.
[ExecuteAlways]
public class HealthZoom : CinemachineExtension
{
[SerializeField] private Transform _player;
[SerializeField] private float _maxZoomBack = 2f;
protected override void PostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage,
ref CameraState state,
float deltaTime)
{
if (stage != CinemachineCore.Stage.Body) return;
var hp = _player.GetComponent<Player>().HealthPercent;
var offset = (1 - hp) * _maxZoomBack;
state.RawPosition -= state.RawOrientation * Vector3.forward * offset;
}
}
Это очень мощно: ты получаешь доступ к pipeline камеры в нужной фазе и меняешь state. Без скриптов на самом GameObject камеры.
Что я обычно настраиваю в каждом проекте
- Один CM Camera в основной gameplay-сцене, с Position Composer и Lookahead 0.4.
- Один CM Collider, чтобы не зарывалась в стены.
- Confiner на 2D-проектах.
- Импульсы для всех hit-событий и взрывов.
- Отдельные CM Camera для cutscene, dialogue zoom, kill cam.
- Settings asset (CM Settings) с дефолтным Damping и FOV для всех камер сразу.
Что не делать
- Не двигай Main Camera напрямую при включённом CM Brain. Cinemachine сразу отзовёт твоё изменение в следующий кадр.
- Не клади 50 CM Camera в одну сцену. Переход с priority работает, но логика становится непрозрачной. Группируй через Timeline или скрипты-менеджеры.
- Не забудь Disabled на неактивных камерах в больших сценах. Активные CM Camera обновляются каждый кадр, даже если не показывают на экран.
- Не настраивай Damping выше 1.5 без причины. Это уже не «мягкость», а «лаг», который игроки чувствуют.
Что почитать
Документация Cinemachine на docs.unity.com — стартовая точка. Серия видео Cinemachine 101 от Unity на YouTube — старые, но базовые концепции не изменились. Adam Myhill — главный разработчик CM, его доклады на Unite (особенно 2018 года) объясняют, почему так сделано.
Главный приём, который я для себя вывел: проектирую камеру до того, как ставлю CM. Сначала на бумаге решаю, как выглядит кадр в gameplay'е (где герой, где UI, какой FOV). Потом подбираю CM-настройки под этот кадр. Если делать наоборот — крутить параметры наугад — потеряешь дни.