Перемещение в Unity: Нормали поверхностей и чистый C#

В этом руководстве описан правильный подход к созданию передвижения персонажа в Unity с использованием нормалей поверхностей и чистого кода C#. Рассмотрены ошибки предыдущего подхода и предложено эффективное решение.

Проблема неправильной реализации движения

Предыдущий подход к перемещению объекта заключался в использовании Force для придания ему ускорения. Это приводило к нескольким проблемам:

  • Непрерывные столкновения: Объект постоянно сталкивался с другими коллайдерами, и физическая подсистема постоянно его выталкивала, создавая эффект «хождения лесенкой».
  • Проблемы с преодолением препятствий: Контроль над объектом затруднялся, он не мог свободно преодолевать препятствия.
  • Избыточная физическая симуляция: Использование Force включало в себя сложные физические взаимодействия (массу, трение и т.д.), которые не нужны для простого перемещения. Это компенсировалось подбором коэффициентов и масс, что приводило к непредсказуемому поведению.

Профессиональный подход к решению задачи

Правильное решение основано на использовании нормалей поверхностей. Цель – двигаться перпендикулярно нормали, обеспечивая плавное скольжение по поверхности. Это обеспечивает контролируемое движение без потерь скорости и застреваний на наклонных поверхностях.

Схема движения по поверхности с использованием нормали (Здесь должен быть рисунок, иллюстрирующий проекцию вектора движения на поверхность)

На рисунке: Saw is normal – нормаль поверхности; Forward – вектор направления движения персонажа. Задача – найти вектор, который будет скользить вдоль поверхности, учитывая направление движения. Проекция вектора Forward на нормаль позволяет двигаться по поверхности, избегая столкновений. Этот подход работает для любых поверхностей, включая вертикальные стены.

Реализация в Unity

Для реализации потребуются три компонента:

  1. Input: Считывает данные с клавиатуры (или другого устройства ввода) и определяет направление движения.
  2. PhysicsMovement: Получает направление движения от Input и, используя компонент SurfaceSlider, проецирует его на поверхность, передвигая объект.
  3. SurfaceSlider: Проецирует вектор направления на нормаль поверхности.

SurfaceSlider содержит три основные части:

  • OnCollisionEnter: При столкновении с коллайдером запоминает нормаль поверхности. В визуальном редакторе отображается красная линия (нормаль поверхности) и белая линия (направление движения). Это упрощение – используется нормаль последней поверхности столкновения. Для более сложных сценариев (несколько поверхностей) потребуется использовать каст коллайдеров (например, Physics.Raycast).
  • Project: Вычисляет вектор движения вдоль поверхности, используя скалярное произведение векторов направления и нормали. Формула: Direction — Vector3.Dot(Direction, normal) * normal. Результат – вектор d, представляющий движение вдоль поверхности.
  • PhysicsMovement: Принимает вектор направления (Direction), преобразует его в вектор движения вдоль поверхности, умножает на скорость и передвигает объект.

Пример кода (фрагменты):

// PhysicsMovement
Vector3 direction = GetInputDirection();
Vector3 surfaceDirection = surfaceSlider.Project(direction);
transform.position += surfaceDirection * speed * Time.deltaTime;

// SurfaceSlider
public Vector3 Project(Vector3 direction) {
    Vector3 normal = lastCollisionNormal;
    return direction - Vector3.Dot(direction, normal) * normal;
}

Input: Получает значения от осей (-1 до 1) для горизонтального и вертикального направления.

Скалярное произведение векторов

Скалярное произведение двух векторов – это сумма произведений соответствующих компонент: A·B = Ax*Bx + Ay*By + Az*Bz.

Его применение в данной задаче:

  • Определение угла между векторами направления и нормали поверхности.
  • Определение возможности передвижения по поверхности.
  • Решение многих других задач (например, определение попадания объекта в поле зрения другого).

Пример расчета:

Для вектора нормали N = (0.5, 0.5) и вектора направления Forward = (-1, 0):

  1. Скалярное произведение: -0.5
  2. Vector3.Dot(Forward, Normal) * Normal = (-0.25, -0.25)
  3. Forward — Vector3.Dot(Forward, Normal) * Normal = (-0.75, 0.25) – Результирующий вектор движения вдоль поверхности.

Использование физической симуляции

Хотя в данном примере используется изменение позиции объекта, можно также реализовать движение через изменение скорости (velocity). Однако, движение должно учитывать топологию уровня, а не просто придавать силы объекту.

Предложенный метод обеспечивает плавное и контролируемое перемещение персонажа в Unity, учитывая топологию уровня и избегая проблем, связанных с избыточной физической симуляцией. Использование нормалей поверхностей и скалярного произведения векторов позволяет создать реалистичный и эффективный геймплей.

Что будем искать? Например,программа