Гид по технологиям

Unity: физический контроллер персонажа — детальное руководство

8 min read Разработка игр Обновлено 24 Nov 2025
Unity: физический контроллер персонажа — руководство
Unity: физический контроллер персонажа — руководство

Геймпад поверх наложенного кода

Контроллер персонажа с физикой — это распространённый способ реализовать реалистичное движение в играх. Такой подход даёт естественные реакции на столкновения и силы, но требует понимания физики Unity (Rigidbody, силы, крутящий момент, коллайдеры и слои). Ниже шаг за шагом описано создание базового контроллера на C#, затем — улучшения, отладка и варианты под разные задачи.

Что мы создаём

Коротко: сцена с плоским ландшафтом (Plane), кубом как моделью игрока (Cube) и камерой третьего лица. Куб становится физическим объектом через Rigidbody. Скрипт на C# добавляет движение вперёд/назад, повороты и прыжок.

Ключевые понятия (в 1–2 строках):

  • Rigidbody — компонент Unity, отвечающий за физическое поведение объекта.
  • AddForce / AddTorque — методы для применения силы и крутящего момента.
  • FixedUpdate — функция Unity для физики, вызывается с фиксированным шагом.

Шаг 1: Создание сцены с игроком и плоскостью

Контроллер персонажа Unity в 3D-пространстве

  1. Откройте Unity и создайте новый проект.
  2. В Hierarchy правой кнопкой — 3D Object → Plane. Это будет ваш тестовый ландшафт. Можно масштабировать Plane для большой зоны тестирования.
  3. В Hierarchy — 3D Object → Cube. Это временная модель игрока.
  4. Выберите Cube → Inspector → Add Component → Rigidbody. Включите Use Gravity.
  5. Разместите Main Camera над кубом; перетащите камеру на Cube в Hierarchy, чтобы сделать её дочерним объектом — камера будет следовать за кубом.

Простой тест: нажмите Play — куб должен упасть на плоскость и камера следовать за ним.

Важно: этот базовый набор компонентов позволяет быстро начать, но для финального проекта замените Cube на модель персонажа с корректными коллайдерами.

Шаг 2: Создание C# файла

Создайте папку Scripts в Project. Внутри — Create → C# Script и назовите файл, например, Character_Control. Откройте файл и убедитесь, что структура класса корректна:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Character_Control : MonoBehaviour {
    void Start() {
    }

    void Update() {
    }
}

Примечание: для работы с физикой используйте FixedUpdate вместо Update, когда применяете силы к Rigidbody — об этом ниже.

Шаг 3: Движение вперёд и назад через AddForce

Добавьте публичные переменные в класс, чтобы задавать Rigidbody и скорость из инспектора:

public Rigidbody rigidbody;
public float speed;

В Start присвойте компонент rigidbody:

void Start() {
    rigidbody = GetComponent();
}

Исходный пример использует Input.GetKey и AddForce:

if (Input.GetKey("w")) {
    rigidbody.AddForce(transform.forward * speed);
}

if (Input.GetKey("s")) {
    rigidbody.AddForce((transform.forward * -1) * speed);
}

Однако есть важные улучшения и замечания:

  • Для физики используйте FixedUpdate вместо Update, чтобы силы применялись согласованно с шагом симуляции.
  • Используйте Time.fixedDeltaTime или ForceMode для предсказуемой силы при разных настройках скорости кадров.
  • Лучше применять относительную силу с ForceMode.VelocityChange, если вы хотите мгновенно менять скорость, или ForceMode.Force для постепенного ускорения.
  • Для плавного управления используйте Input.GetAxis(“Vertical”) вместо отдельных GetKey — это даёт аналоговые значения (от -1 до 1).

Пример улучшенного фрагмента:

void FixedUpdate() {
    float moveInput = Input.GetAxis("Vertical"); // -1..1
    Vector3 force = transform.forward * moveInput * speed;
    rigidbody.AddForce(force, ForceMode.Force);
}

Если куб начинает катиться или крутиться, зайдите в Rigidbody и зафиксируйте вращение по осям X и Z (Constraints → Freeze Rotation X,Z). Этот шаг предотвращает переворачивания при столкновениях.

Шаг 4: Повороты через AddTorque

Добавьте переменную torque:

public float torque;

Исходный код использует Input.GetAxis(“Horizontal”) и AddTorque:

if (Input.GetKey("d")) {
    float turn = Input.GetAxis("Horizontal");
    rigidbody.AddTorque(transform.up * torque * turn);
}

if (Input.GetKey("a")) {
    float turn = Input.GetAxis("Horizontal");
    rigidbody.AddTorque(transform.up * torque * turn);
}

Упрощённый и улучшенный вариант в FixedUpdate:

void FixedUpdate() {
    float moveInput = Input.GetAxis("Vertical");
    float turnInput = Input.GetAxis("Horizontal");

    rigidbody.AddForce(transform.forward * moveInput * speed, ForceMode.Force);
    rigidbody.AddTorque(transform.up * turnInput * torque, ForceMode.Force);
}

Советы по настройке:

  • Меняйте массу (Mass) и затухание (Drag) у Rigidbody для регулировки инерции и торможения.
  • Torque зависит от массы; если персонаж слишком медленно поворачивается, увеличьте torque или уменьшите массу.
  • Для более игрового (не физического) управления используйте transform.Rotate вместе с подконтролем коллизий, но в этом случае вы теряете реакцию физики.

Пример рекомендованных начальных значений (пример): Mass = 1, Drag = 1, torque = 2.

Шаг 5: Прыжок с контролем высоты

Прыжок требует контроля: игрок должен подпрыгивать ограниченно и не «многократно» в воздухе. Для этого используйте флаг isJumping и проверку на землю.

Исходный примитивный пример из текста:

private bool isJumping = false;

if (!isJumping) {
    if (Input.GetKeyDown("space")) {
        isJumping = true;
        rigidbody.AddForce(transform.up * speed * 120);
        rigidbody.angularVelocity = Vector3.zero;
        Invoke("Move_Setter", 0.8f);
    }
}

void Move_Setter() {
    isJumping = false;
}

Этот код работает, но имеет недостатки: Invoke с фиксированным временем не учитывает высоту прыжка, платформы или возможность восстановления в воздухе. Лучше определить, находится ли объект на земле, через Raycast или коллайдер, и использовать физически корректное приложение силы с ForceMode. Вот улучшенный подход.

Пример улучшенного кода для прыжка с проверкой земли:

public float jumpForce = 5f;
public Transform groundCheck; // пустой объект внизу модели
public float groundCheckDistance = 0.1f;
public LayerMask groundLayers; // слои, считающиеся землёй
private bool isGrounded = false;

void FixedUpdate() {
    // движение и поворот как выше
}

void Update() {
    // проверка ввода прыжка в Update
    if (Input.GetKeyDown(KeyCode.Space) && isGrounded) {
        rigidbody.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    }
}

void LateUpdate() {
    // простая проверка на землю
    isGrounded = Physics.Raycast(groundCheck.position, Vector3.down, groundCheckDistance, groundLayers);
}

Пояснения:

  • groundCheck — пустой объект (empty GameObject) на уровне стоп персонажа. Raycast проверяет, есть ли земля под персонажем.
  • ForceMode.Impulse применяется для мгновенного импульса (подходит для прыжка).
  • Это надёжнее, чем «таймер», так как прыжок снова возможен только после реального контакта с землёй.

Общие улучшения и лучшие практики

  • FixedUpdate для всех действий, изменяющих Rigidbody (AddForce, AddTorque, MovePosition, MoveRotation).
  • Input собирайте в Update (например, флаги или оси), а применяйте в FixedUpdate.
  • Нормализуйте векторы перед умножением на скорость, если комбинируете направления (чтобы диагональная скорость не была больше).
  • Используйте constraints в Rigidbody, чтобы отключить ненужные степени свободы (например, зафиксировать ось Y вращения для 2D-плоскости).
  • При необходимости используйте Physics Materials для управления скольжением и сцеплением поверхностей.
  • Для персонажа, требующего точного контроля (платформер, шутер), рассмотрите использование CharacterController или кинематического управления, вместо физики.

Отладка и распространённые проблемы

Important: если объект крутится или ведёт себя нестабильно:

  • Проверьте коллайдеры: пересекающиеся или слишком большие коллайдеры могут создавать непредсказуемые силы.
  • Заморозьте ненужные вращения (Freeze Rotation) или используйте constraints.
  • Убедитесь, что не применяете силы одновременно в Update и FixedUpdate.
  • Проверяйте консоль Unity на ошибки компиляции и предупреждения о несоответствиях типов.

Если прыжки срабатывают несколько раз подряд или персонаж «застревает» в воздухе — используйте Raycast/OnCollisionEnter для надёжного определения контакта с землёй.

Альтернативные подходы

  1. CharacterController: компонент Unity, предоставляющий методы Move и SimpleMove. Он не использует Rigidbody и даёт точный контроль над движением (удобно для платформ и шутеров).
  2. Kinematic Rigidbody: используйте Rigidbody в режиме kinematic и вручную управляйте позицией через MovePosition и MoveRotation.
  3. Контроль через NavMeshAgent: для NPC и навигации на уровне сцены.
  4. Смешанный подход: физика для столкновений, но управление через контролируемое изменение позиции.

Когда физика не подходит:

  • Нужен стабильный, предсказуемый контроль (например, в соревновательных играх с быстрым откликом).
  • Взаимодействия с физикой приводят к слишком затруднённым багам (задевания, «флиппинг»).

Стратегия тестирования и Критерии приёмки

Критерии приёмки:

  • Персонаж движется вперёд/назад при нажатии W/S с предсказуемой скоростью.
  • Персонаж поворачивается влево/вправо при нажатии A/D без заметного дрожания.
  • Прыжок срабатывает только при контакте с землёй; повторный прыжок в воздухе невозможен.
  • При фиксации вращений по X/Z куб не переворачивается при столкновениях.

Тест-кейсы:

  • Нажать W: персонаж ускоряется вперед.
  • Нажать S: персонаж движется назад.
  • Нажать A/D: поворот вокруг оси Y с ожидаемой скоростью.
  • Прыжок: нажать пробел на земле — персонаж подпрыгивает; нажать пробел в воздухе — прыжок не срабатывает.
  • Столкновение со стеной: персонаж не проходит сквозь коллайдер.

Чек-листы по ролям

Для разработчика:

  • Добавить Rigidbody и Collider.
  • Создать скрипт управления и присвоить его объекту.
  • Тестировать FixedUpdate и Update разделение.
  • Настроить groundCheck и слои земли.

Для дизайнера уровня:

  • Проверить геометрию коллайдеров на сцене.
  • Убедиться, что навигационные области не пересекаются с физическими объектами.

Для QA:

  • Выполнить все тест-кейсы из Критерии приёмки.
  • Проверить экстремальные случаи (высокая скорость, наклонные поверхности).

Примеры улучшенных скриптов — «чистая» версия

Ниже пример компактного, практичного скрипта, который объединяет всё вышеописанное (комментарии внутри):

using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class SimplePhysicsCharacter : MonoBehaviour {
    public float speed = 5f;
    public float torque = 2f;
    public float jumpForce = 5f;

    public Transform groundCheck;
    public float groundCheckDistance = 0.1f;
    public LayerMask groundLayers;

    private Rigidbody rb;
    private float moveInput;
    private float turnInput;
    private bool jumpRequest;
    private bool isGrounded;

    void Start() {
        rb = GetComponent();
    }

    void Update() {
        // Сбор ввода в Update
        moveInput = Input.GetAxis("Vertical");
        turnInput = Input.GetAxis("Horizontal");
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded) {
            jumpRequest = true;
        }

        // Проверяем землю
        isGrounded = Physics.Raycast(groundCheck.position, Vector3.down, groundCheckDistance, groundLayers);
    }

    void FixedUpdate() {
        // Движение и поворот в физической петле
        rb.AddForce(transform.forward * moveInput * speed, ForceMode.Force);
        rb.AddTorque(transform.up * turnInput * torque, ForceMode.Force);

        if (jumpRequest && isGrounded) {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            jumpRequest = false;
        }
    }
}

Этот шаблон легко настраивается через Inspector и безопасен с точки зрения разделения ввода и применения сил.

Когда подход с Rigidbody не подойдёт (контрпримеры)

  • Платформер с прыжками «по пиксельной» точности: физика может внести непредсказуемость.
  • Сетевые игры с авторитетным сервером: передача физического состояния между клиентами — сложная задача. Часто используют предсказание и репликацию, либо кинематические методы.
  • 2D-игры, где требуется строгое поведение по оси — лучше использовать специализированные 2D-компоненты.

Ментальные модели и эвристики

  • Сила (AddForce) — это непрерывное влияние, оно постепенно меняет скорость.
  • Импульс (ForceMode.Impulse) — мгновенное изменение скорости (удар, прыжок).
  • Крутящий момент (AddTorque) — вращение вокруг оси; комбинируйте с ограничениями, чтобы избегать переворотов.
  • Разделяй ввод и физику: считывай ввод в Update, применяй в FixedUpdate.

Советы по производительности

  • Минимизируйте частые вызовы Raycast на каждом кадре для множества объектов; группируйте проверки или используйте триггерные коллайдеры.
  • Для крупных сцен используйте слои и LayerMasks, чтобы Raycast проверял только релевантные поверхности.
  • Отключайте физику для объектов за пределами зоны интереса (Sleeping Mode).

Совместимость и миграция

  • Скрипты, использующие устаревшие API, могут потребовать приведения типов после обновления Unity. Всегда тестируйте на целевой версии движка.
  • Если проект переходит от физического подхода к CharacterController, потребуется переработать логику столкновений и анимаций.

Краткая сводка

  • Используйте Rigidbody и AddForce/AddTorque для естественного физического движения.
  • Применяйте силы в FixedUpdate, собирайте ввод в Update.
  • Для прыжков используйте Raycast/OnCollision для определения контакта с землёй.
  • Рассмотрите альтернативы (CharacterController, kinematic), если нужна более строгая предсказуемость.

Если вы хотите, я могу подготовить готовый пак скриптов с настройками Inspector, или адаптировать пример под 2D/серверную синхронизацию.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как сделать правый клик на Chromebook
Chromebook

Как сделать правый клик на Chromebook

Не удалось инициализировать Direct3D — решения
Техподдержка

Не удалось инициализировать Direct3D — решения

Исправить Data Retrieval в Diablo 4 на Steam
Игры

Исправить Data Retrieval в Diablo 4 на Steam

Open Graph в WordPress — настройка мета‑тегов
WordPress SEO

Open Graph в WordPress — настройка мета‑тегов

getconf: адаптивные скрипты для разных Linux
Linux

getconf: адаптивные скрипты для разных Linux

Проверка входов в Windows — успешные и неудачные попытки
Безопасность Windows

Проверка входов в Windows — успешные и неудачные попытки