Содержание статьи

Камера от первого лица – основа шутеров, симуляторов и многих других жанров. В Unity её реализация требует точной настройки компонентов CharacterController и Camera, а также обработки ввода через Input System или Legacy Input. Без правильной конфигурации движения будут дёргаными, а повороты – неточными. В этом гайде разберём минимально необходимые шаги: от привязки камеры к игроку до настройки чувствительности мыши и ограничения вертикального обзора.
Первый шаг – создание пустого объекта Player с компонентом CharacterController. Этот контроллер отвечает за физическое взаимодействие с миром: столкновения, гравитацию и передвижение. Стандартные параметры Radius = 0.5 и Height = 2 подойдут для большинства случаев, но для узких проходов их можно уменьшить. Добавьте дочерний объект Camera и расположите его на уровне глаз персонажа – примерно Y = 1.6.
Для управления камерой потребуется скрипт на C#. Используйте Update() для обработки ввода и LateUpdate() для применения поворотов – это предотвратит конфликты с движком физики. Чувствительность мыши задаётся переменной float mouseSensitivity = 100f, а ограничение вертикального обзора реализуется через Mathf.Clamp() с диапазоном -90f до 90f. Не забудьте заблокировать курсор через Cursor.lockState = CursorLockMode.Locked – иначе управление будет неудобным.
Последний шаг – настройка движения. Вектор перемещения формируется из осей Horizontal и Vertical, а скорость задаётся константой moveSpeed = 5f. Для реалистичного ускорения используйте Vector3.SmoothDamp() или CharacterController.Move() с учётом Time.deltaTime. Гравитация добавляется через переменную gravity = -9.81f, которая применяется к вектору движения каждый кадр. Готовый скрипт весит около 50 строк кода – этого достаточно для базовой функциональности.
Настройка базового игрового объекта для камеры
Перетащите основную камеру (Main Camera) в PlayerCameraRoot, сделав её дочерним объектом. Сбросьте её локальные координаты и поворот (Transform → Reset), чтобы она находилась в центре родителя. В настройках камеры задайте Field of View (FOV) в диапазоне 60–90 градусов – стандартные значения для FPS. Отключите Audio Listener, если он не нужен, чтобы избежать конфликтов с другими слушателями в сцене.
Для корректной работы от первого лица добавьте скрипт управления камерой на PlayerCameraRoot. В коде используйте Transform.Rotate для горизонтального вращения родителя (по оси Y) и Mathf.Clamp для ограничения вертикального угла обзора камеры (например, от -80 до 80 градусов). Это предотвратит «переворот» камеры при резких движениях мыши.
Добавление скрипта управления движением персонажа
Создайте новый C#-скрипт в папке Scripts и назовите его PlayerMovement. Подключите его к игровому объекту с камерой первого лица. В методе Update() реализуйте обработку ввода с клавиатуры и мыши через Input.GetAxis(). Для движения используйте векторы Vector3.forward, Vector3.right и метод Transform.Translate(), умножая их на скорость (moveSpeed) и время кадра (Time.deltaTime).
Для плавного поворота камеры по горизонтали добавьте переменную rotationSpeed (рекомендуемое значение: 100–300) и обработайте ось мыши Mouse X. Примените вращение через Transform.Rotate() с вектором Vector3.up. Ограничьте вертикальный поворот (ось Mouse Y) диапазоном от -90 до 90 градусов, используя Mathf.Clamp() и отдельную переменную для хранения текущего угла наклона.
| Параметр | Тип данных | Значение по умолчанию | Описание |
|---|---|---|---|
moveSpeed |
float |
5.0f | Скорость перемещения персонажа |
rotationSpeed |
float |
200.0f | Чувствительность мыши |
jumpForce |
float |
5.0f | Сила прыжка (если используется Rigidbody) |
Для реализации прыжка добавьте компонент Rigidbody к персонажу и настройте его: отключите вращение по осям X и Z (Freeze Rotation), установите массу (mass) в 1–3. В скрипте создайте ссылку на Rigidbody и метод Jump(), который проверяет нажатие клавиши Space и наличие контакта с землёй (используйте Physics.Raycast() с длиной луча 0.1–0.2). Примените силу через Rigidbody.AddForce() с вектором Vector3.up * jumpForce.
Оптимизируйте движение, добавив проверку на ускорение при зажатой клавише Shift. Умножьте moveSpeed на коэффициент (например, 1.5) при срабатывании условия Input.GetKey(KeyCode.LeftShift). Для предотвращения «скольжения» по наклонным поверхностям настройте параметр Drag у Rigidbody в диапазоне 1–5 или используйте CharacterController вместо Rigidbody, если требуется более точное управление.
Реализация вращения камеры с помощью мыши
Вращение камеры в Unity через мышь требует обработки осей Mouse X и Mouse Y. Эти оси возвращают смещение курсора по горизонтали и вертикали за кадр. Для доступа к ним используйте Input.GetAxis("Mouse X") и Input.GetAxis("Mouse Y"). Умножьте полученные значения на чувствительность (например, 2–5 для стандартных настроек) и Time.deltaTime, чтобы сгладить движение и сделать его независимым от частоты кадров.
Создайте публичный параметр public float mouseSensitivity = 3f; в скрипте камеры. Это позволит настраивать чувствительность через инспектор без изменения кода. Для предотвращения резких скачков при первом движении мыши добавьте проверку: если абсолютное значение смещения меньше 0.01, обнуляйте его. Такой подход устраняет «дёрганье» при малейшем движении курсора.
Вращение по горизонтали реализуйте через поворот родительского объекта камеры (например, пустого GameObject с именем PlayerBody). Используйте transform.Rotate(Vector3.up * mouseX), где mouseX – обработанное значение оси Mouse X. Это предотвратит наклон камеры при поворотах и сохранит вертикальную ось стабильной.
Для вертикального вращения применяйте поворот самой камеры вокруг локальной оси X. Однако ограничьте углы наклона, чтобы избежать переворота камеры. Используйте Mathf.Clamp() для фиксации угла в пределах, например, от -90 до 90 градусов. Пример кода: xRotation -= mouseY; xRotation = Mathf.Clamp(xRotation, -90f, 90f); transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);.
Инвертируйте вертикальное вращение, если это необходимо для удобства игрока. Добавьте булевый параметр public bool invertY = false; и модифицируйте расчёт: mouseY = invertY ? -mouseY : mouseY;. Это позволит игрокам выбирать привычный способ управления без изменения логики скрипта.
Для плавного замедления вращения при отпускании мыши используйте линейную интерполяцию. Создайте переменную private float currentXRotation; и обновляйте её через currentXRotation = Mathf.Lerp(currentXRotation, xRotation, 5f * Time.deltaTime);. Это сгладит резкие остановки и добавит реалистичности движению.
Исключите вращение камеры, когда курсор заблокирован или игра приостановлена. Проверяйте состояние курсора через Cursor.lockState == CursorLockMode.Locked и Time.timeScale > 0. Добавьте эти условия в начало метода Update(), чтобы избежать ненужных вычислений и багов при паузе.
Ограничение вертикального угла обзора камеры

Вертикальное ограничение угла обзора предотвращает неестественное вращение камеры за пределы реалистичных значений, например, когда персонаж смотрит строго вверх или вниз. Без этого игрок может «застрять» в неудобных ракурсах, а физика взаимодействия с объектами сломается. Реализуется через модификацию скрипта управления камерой с использованием Mathf.Clamp() для угла наклона.
Стандартные пределы для FPS-камеры: от -80° до +80°. Эти значения обеспечивают баланс между свободой обзора и игровым комфортом. При превышении ±90° камера переворачивается, нарушая ориентацию игрока. Для реализма в шутерах часто используют диапазон -60°/+60°, чтобы избежать «сломанных» ракурсов при прицеливании.
Пример кода для ограничения вертикального вращения:
- Создайте переменную
private float verticalRotation = 0f;для хранения текущего угла. - В методе
Update()считайте ввод мыши по оси Y:float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; - Обновите
verticalRotationс учетом ограничений:verticalRotation = Mathf.Clamp(verticalRotation - mouseY, -80f, 80f); - Примените вращение к камере:
playerCamera.transform.localEulerAngles = new Vector3(verticalRotation, 0f, 0f);
Для плавного ограничения используйте Quaternion.Slerp() вместо резкого обрезания угла. Это полезно в играх с динамичным движением, где резкие остановки камеры вызывают дискомфорт. Пример:
float targetRotation = Mathf.Clamp(verticalRotation - mouseY, -80f, 80f); playerCamera.transform.localRotation = Quaternion.Slerp( playerCamera.transform.localRotation, Quaternion.Euler(targetRotation, 0f, 0f), Time.deltaTime * 10f );
В многопользовательских играх синхронизируйте ограничения на клиенте и сервере. Разница в углах обзора между игроками приводит к десинхрону прицеливания. Используйте [SyncVar] в Unity Netcode или аналогичные механизмы для передачи текущего угла наклона камеры.
Для VR-проектов ограничения работают иначе. Вместо фиксированных углов используйте XRInputSubsystem и проверяйте физические ограничения шлема. Например, Oculus Quest 2 имеет аппаратный лимит ±50° по вертикали. Превышение этих значений вызывает ошибки отслеживания.
Тестируйте ограничения на разных разрешениях экрана. На мониторах с соотношением сторон 21:9 или 32:9 камера может вести себя некорректно из-за искажений перспективы. Добавьте проверку соотношения сторон в скрипт и корректируйте пределы углов динамически.
Для оптимизации производительности избегайте вычислений в LateUpdate(), если камера не зависит от других объектов. Перенесите логику ограничения в Update() и применяйте финальные значения вращения в LateUpdate(), чтобы избежать дрожания при синхронизации с движением персонажа.
Настройка скорости перемещения и чувствительности мыши
Скорость перемещения персонажа задаётся через компонент CharacterController или Rigidbody, но ключевые параметры определяются в скрипте управления. В методе Update() используйте переменные moveSpeed (например, 5.0f) и runMultiplier (1.5–2.0) для ускорения при зажатой клавише Shift. Для плавного изменения скорости применяйте Mathf.Lerp с коэффициентом 0.1–0.3, чтобы избежать резких рывков. Если персонаж «плывёт» по наклонным поверхностям, уменьшите slopeLimit в CharacterController до 45° и добавьте проверку на землю через isGrounded.
Чувствительность мыши настраивается через переменную mouseSensitivity (рекомендуемый диапазон: 100–500). В скрипте управления камерой умножайте Input.GetAxis(«Mouse X») и Input.GetAxis(«Mouse Y») на это значение. Для инвертирования оси Y добавьте флаг invertY и умножайте ось на -1 при его активации. Чтобы избежать «дрожания» камеры на высоких значениях, ограничьте углы наклона по вертикали через Mathf.Clamp в пределах -90° до 90°.
Для адаптации под разные разрешения экрана нормализуйте чувствительность, умножив её на Screen.width / 1920f (или аналогично для высоты). Это компенсирует разницу в пиксельном разрешении мыши. Если игра поддерживает геймпад, добавьте отдельную переменную gamepadSensitivity (обычно в 2–3 раза ниже мышиной) и переключайте её при обнаружении ввода с контроллера через Input.GetJoystickNames().
Тестируйте настройки на разных устройствах: на ноутбуках с тачпадом чувствительность должна быть ниже (50–150), а на игровых мышах с высоким DPI – выше (300–800). Для калибровки используйте тестовый уровень с мишенями на разном расстоянии. Если камера «залипает» при резких движениях, добавьте демпфирование через Vector3.SmoothDamp с временем сглаживания 0.05–0.1 секунды.
Сохраняйте настройки в PlayerPrefs для удобства пользователя: PlayerPrefs.SetFloat(«MouseSensitivity», mouseSensitivity). При старте игры загружайте их через PlayerPrefs.GetFloat с дефолтным значением. Для динамической подстройки во время игры реализуйте ползунок в меню, который будет обновлять переменные в реальном времени без перезапуска сцены.
Добавление столкновений камеры с объектами сцены

Создайте скрипт CameraCollision.cs и прикрепите его к камере. В методе Update() используйте Physics.SphereCast() для проверки столкновений по направлению взгляда. Параметры: начальная точка – позиция игрока, радиус – 0.2, направление – вектор от игрока к камере, максимальная дистанция – расстояние до камеры. Если луч обнаруживает препятствие, смещайте камеру к точке столкновения, вычитая радиус коллайдера из расстояния.
Для плавного перемещения камеры при столкновениях используйте Vector3.Lerp() или Mathf.SmoothDamp(). Установите скорость интерполяции в диапазоне 5–15 единиц в секунду – это обеспечит баланс между отзывчивостью и плавностью. Исключите резкие скачки, ограничив минимальное расстояние до препятствия 0.1 единицей, чтобы камера не «прилипала» к стенам.
Оптимизируйте производительность, добавив проверку на изменение позиции игрока перед выполнением SphereCast(). Если игрок не движется, пропускайте расчет столкновений. Для сложных сцен используйте маски слоев (LayerMask) и ограничивайте количество проверяемых объектов. Тестируйте на разных типах поверхностей: наклонные плоскости, углы и объекты с нестандартными коллайдерами требуют дополнительной настройки радиуса и смещения.
Синхронизация анимаций персонажа с движением камеры

В камере от первого лица критически важно, чтобы анимации персонажа (особенно рук и оружия) совпадали с движениями камеры. Даже минимальное рассогласование создаёт эффект «плавающего» оружия, разрушая иммерсию. Решение – привязка анимаций к Animator и синхронизация через Transform камеры в реальном времени.
Используйте Animator.SetFloat() для передачи скорости движения камеры в параметры аниматора. Например, параметр "Speed" должен обновляться каждый кадр на основе camera.transform.forward * Input.GetAxis("Vertical"). Это позволит анимациям ходьбы и бега плавно переходить друг в друга без задержек.
- Для оружия создайте отдельный
GameObjectсAnimator, дочерний к камере. - В скрипте камеры добавьте ссылку на этот аниматор и обновляйте его параметры через
Update(). - При стрельбе вызывайте
animator.Play("Fire")только после проверкиInput.GetButtonDown("Fire1").
Отключите Apply Root Motion в компоненте Animator персонажа – иначе анимации будут перемещать модель независимо от физики. Вместо этого управляйте движением через CharacterController или Rigidbody, а анимации используйте только для визуального отображения.
Для плавного поворота головы персонажа (если она видна) применяйте Quaternion.Slerp() между текущим и целевым вращением камеры. Целевое вращение рассчитывайте как Quaternion.Euler(camera.transform.eulerAngles.x * 0.5f, 0, 0) – это уменьшит резкость движений и создаст эффект естественного отставания.
Тестируйте синхронизацию на разных FPS. При 30 кадрах в секунду анимации могут «проскакивать», а при 144 – выглядеть слишком резкими. Используйте Time.deltaTime для нормализации скорости анимаций и корректируйте параметры Animator через Mathf.Lerp() для сглаживания переходов.
Если оружие «дёргается» при поворотах камеры, проверьте порядок выполнения скриптов в Script Execution Order (Edit → Project Settings → Script Execution Order). Скрипт камеры должен обновляться раньше скрипта анимаций. Также убедитесь, что Update() в скрипте камеры вызывается до LateUpdate() в скрипте анимаций – это гарантирует, что анимации получат актуальные данные о положении камеры.
Оптимизация производительности камеры в больших сценах

Первый шаг – ограничение области рендеринга через Camera.farClipPlane. В сценах с открытыми пространствами значение по умолчанию (1000 единиц) часто избыточно. Для городских уровней достаточно 200–300, для природных ландшафтов – 500–700. Уменьшение этого параметра снижает нагрузку на GPU за счёт исключения объектов за пределами видимости, но требует тестирования на «просвечивание» геометрии.
Используйте Occlusion Culling для статичных объектов. В Unity эта система работает на этапе сборки сцены, анализируя видимость мешей из заранее определённых точек. Для динамичных сцен добавьте Occlusion Area вокруг камеры с радиусом 50–100 единиц – это позволит исключать объекты, скрытые за стенами или рельефом, без ручной настройки.
Отключите рендеринг слоёв, невидимых для камеры. Создайте отдельный слой для объектов, которые всегда за кадром (например, триггеры или вспомогательные меши), и исключите его через Camera.cullingMask. В сценах с зеркалами или порталами используйте отдельные камеры с урезанными слоями, чтобы избежать дублирования рендеринга.
Для камер с высоким разрешением (например, 4K) включите Dynamic Resolution. Эта функция автоматически снижает разрешение рендеринга при падении FPS ниже заданного порога (например, 50 кадров). Настройте минимальный масштаб в Universal Render Pipeline Asset на уровне 0.7–0.8, чтобы избежать заметного размытия.
Кэшируйте результаты Physics.Raycast и Physics.OverlapSphere, если камера часто проверяет столкновения. Для FPS-камер с постоянным отслеживанием препятствий используйте Physics.SphereCastNonAlloc с предварительно выделенным массивом на 5–10 элементов – это сократит аллокации памяти на 90%.
Замените стандартные шейдеры на упрощённые версии для удалённых объектов. В LOD Group добавьте последний уровень с шейдером Unlit/Color или Mobile/Diffuse, который не использует освещение и тени. Для объектов на расстоянии более 150 единиц это снизит нагрузку на GPU на 30–40%.
Оптимизируйте постобработку. Эффекты вроде Bloom или Depth of Field требуют дополнительных проходов рендеринга. Отключите их для камер, где они не критичны, или используйте Volume Blending с приоритетом 0 для основной камеры и 1 для камер с постобработкой. В URP включите Fast Approximate Anti-Aliasing (FXAA) вместо TAA – он быстрее на 15–20%.
Для VR или мультикамерных сцен используйте Single Pass Instanced рендеринг. В настройках проекта выберите этот режим вместо Multi Pass – это сократит количество вызовов отрисовки вдвое. Для камер с одинаковыми параметрами (например, зеркала) применяйте Camera.CopyFrom, чтобы избежать дублирования настроек и снизить нагрузку на CPU.
