Найти в Дзене
NoT ZaTroTing

Idle игра на Unity #2 - Перемещение

Оглавление

Здравствуйте! Сегодня мы создадим персонажа, который сможет передвигаться по локации.

Что за передвижение?

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

Реализация

Весь код с примером использования будет в конце статьи по ссылке.

Итак, начнем реализовывать.

Для начала создадим скрипт передвижения Movement2D. Какие параметры должны быть у передвижения:

  • Влияние гравитации на объект.
  • Скорость передвижения;
  • Максимальный угол взбирания;
  • Высота прыжка;

Далее создадим методы Jump и Move для задания движения:

  • Метод Jump при вызове должен задавать импульс движения вверх. Перед тем как задать его, произведет проверку на то, может ли он прыгнуть.
  • Метод Move должен передвигать объект. В качестве параметра будет выступать направление, в какую сторону двигаться, т.е. Vector2. Помимо этого, он будет вычислять "правильное" направление движения и рассчитывать текущую силу прыжка и гравитации.

Что я подразумеваю под "правильным" направлением?

"Правильное" направление это то направление, в которое действительно должен двигаться объект.

Поясню на примере:

-2

Зеленым вектором показан вектор нормали, действующий на объект передвижения.

Красным вектором показан вектор, который согласован с задающим направлением движения. Именно он и передается в метод Move.

Желтым показан "правильный" вектор движения. Именно туда и должен двигаться объект.

Как можно заметить, подобие нужного вектора можно получить с помощью суммы двух других. Однако, чтобы компенсировать возможные расхождения, воспользуемся формулой:

trueVector = inputMovement - (inputMovement, normal) * normal

Где:

  • trueVector - нужный нам вектор;
  • inputMovement - вектор заданного движения;
  • normal - вектор нормали;
  • (inputMovement, normal) - скалярное произведение двух векторов.

Информацию о соприкосновении с объектами будем получать через OnCollisionStay2D. Также надо отслеживать, когда мы выходим из контакта, для этого используем OnCollisionExit2D. Выделим под это отдельный класс SurfaceSlider с методом Project, который будет возращать полную информацию о соприкосновениях.

Почему OnCollisionStay, а не OnCollisionEnter?

В процессе тестирования возникали ошибки, когда при наклонным поверхностях готовый скрипт думал, что он падает, а потому нельзя было прыгнуть и перемещение было затруднительным.

Также необходимо создать структуру, которая будет хранить в себе информацию, которую будет возвращать метод Project. OnSurfaceInfo с следующими полями:

  • Angle - угол между между вектором движения и вектором нормали;
  • Normal - вектор нормали;
  • Movement - "правильный" вектор движения;
  • HasContactWithSolidSurface - контактирует ли объект с твердой поверхностью;
  • AngleStraightDown - угол между вектором нормали и вектором, направленным прямо вниз.

SurfaceSlider

Реализуем SurfaceSlider.

Единственным внешним методом этого класса будет Project.

Структура метода Project
Структура метода Project

Рассмотрим основные моменты:

  • Angle = angle % 90 - здесь деление происходит для того, чтобы компенсировать разницу в направлении наклона объектов;
  • AngleStraightDown - как бы странно это не выглядело, что угол считается с вектором направленным вверх, но это легко объяснить: при передвижении по поверхностям вектор нормалей направлен вверх, а потому и рассматривать нужно тоже с вектором, направленным вверх;
  • Далее идет условие, контактирует ли объект с поверхностью, если нет, то передвижение происходит свободно.

Рассмотрим поведение внутри блока if:

-4
  • MoveWithBigAngle - метод при вскарабкивании;
  • MoveWithLowAngle - метод при спуске.
-5

При контакте с объектами мы добавляем их в список коллизий; при выходе мы их оттуда удаляем. При входе/выходе мы обновляем данные о текущей коллизии:

-6

Movement2D

Рассмотрим для начала метод прыжка.

Здесь все просто, сначала происходит проверка на то, можно ли прыгнуть, затем задается сила прыжка и обнуляется время в полете.

-7

Далее рассмотрим метод Move.

В этих строках мы добавляем время в полете и находим направление, в котором следует двигаться объекту по оси X.

-8

Далее определяем состояние, можно ли прыгать с данной поверхности, а затем подсчитываем влияние гравитации и прыжка.

-9

Заключительным этапом является передвижение:

-11

Заключение

Моя реализация передвижения позволяет перемещать объекты по сцене с задействием физики. Для правильного взаимодействия используется компонент Surface, который позволяет задействовать только те объекты для передвижения, которые были заданы заранее, также отдельный класс позволяет спокойно расширять его.

Ссылка на репозиторий (на данный момент репозиторий приватный, как только найдется время причесать код, открою снова).