Найти тему
Votline

Реализация контроллера движения в Godot Engine 3D

В мире разработки 3D игр на движке Godot Engine создание эффективного контроллера движения игрового персонажа является ключевым аспектом. В этой статье я расскажу о том, как создать свой собственный movement controller для вашей 3D игры на собственном опыте.

Для начала нажмите правой кнопкой мыши по папке 'res://' и выберите 'Create New', затем 'Scene'. Это позволит нам удобно организовать наш проект и начать работу над контроллером движения.

Учитывая, что мы разрабатываем 3D игру, в появившемся окне выберите '3D Scene' и дайте ей название 'Main'. Это будет нашей основной сценой.

-2

Прекрасно, мы сделали первый шаг. Теперь перейдем ко второму. Нам необходимо создать еще одну сцену для удобства, но уже выбрав 'Node', а именно 'CharacterBody3D'. Назовем эту сцену 'player'. В эту сцену нам нужно добавить 'CollisionShape3D', 'MeshInstance3D', 'Node3D', а также 'Camera3D'. Тем самым создадим такую иерархию:

-3

"Но что такое Node3D? Это голова нашего персонажа, которую мы будем использовать в будущем. Давайте назовем ее 'Head' и переместим в соответствующее место, где будет расположена голова нашего персонажа.

Теперь перейдем к выбору необходимой коллизии в CollisionShape3D. Лучшим выбором для нас будет CapsuleShape3D. Повторим ту же операцию и с MeshInstance3D:

-4
-5

Отлично, теперь нажмем правой кнопкой мыши по нашему CharacterBody3D (player) и выберем 'Attach Script'. В качестве шаблона выберем 'CharacterBody3D: Basic Movement'.

-6

Мы уже можем запустить нашу игру и персонаж будет двигаться, но только по стрелочкам. Как это исправить? Наводимся на Project -> Project Settings -> Input Map и добавляем нужные нам клавиши.

-7

-8

Теперь немного изменим наш код:

Давайте рассмотрим наш скрипт более детально:

  • В строках 3-8 мы объявляем и инициализируем переменные, которые нам понадобятся для управления движением. Это происходит в функции _ready(), которая запускается один раз при старте нашей игры. Можно это делать и вне функции, но я считаю такую инициализацию удобной. Обратите внимание, что мы указываем типы переменных, например, 'var direction: Vector3', хотя это не обязательно.
  • Наши основные операции выполняются в строке 10 в функции _physics_process(delta). Эта функция вызывается постоянно в течение игры и принимает аргумент delta, который представляет собой время, прошедшее с последнего кадра. Мы будем использовать эту переменную для создания более плавного падения нашего персонажа под воздействием гравитации.
  • В строках 13 мы создаём функцию move() которую будем вызывать в _physics_process(delta) для большей красоты кода.
  • В строках 14-15 мы проверяем, находится ли наш персонаж на земле, используя встроенную функцию is_on_floor(). Если наш персонаж находится на земле, то никаких дополнительных действий не происходит. В противном случае, если персонаж не на земле, мы начинаем плавное падение.
  • В строках 17-18 у нас реализована механика прыжка. Здесь мы проверяем, была ли нажата клавиша прыжка (обычно это клавиша 'Пробел') и находится ли наш игрок на земле. Если да, то наш персонаж выполняет прыжок вверх. Однако в моей игре прыжкок не предусмотрен, поэтому я просто удалю эти строки из скрипта.
  • Наконец дошли до самого сочного. В строках 20-29 у нас реализована самая главная механика - механика передвижения:
  1. Для начала мы получаем вектор ввода от игрока используя Input.get_vector(). Если мы выведем его в консоль, то вывод будет такой: (1 или 0 или -1, 1 или 0 или -1).
  2. После этого мы определяем направления движения объекта:
    transform.basis нужен нам для опредения поворта и мастабирования объекта.
    Vector3(input_dir.x, 0, input_dir.y) Это вектор, представляющий направление движения от игрока. input_dir.x и input_dir.y ввод от игрока по осям X и Y соответственно. Значение по оси Z устанавливается в 0.
    normalized() нужен нам для нормализации вектора, приводя его к единичной длине(=1). Это требуется для того, чтобы скорость игрока не зависила от направления движения.
  3. Если персонаж двигается, то мы плавно увеличиваем скорость, иначе устанавливаем её на 0. Мы могли бы упростить эту строку без использования линейной интерполяции(lerp), однако я предпочитаю, чтобы скорость в нашей игре увеличивалась плавно.
  4. В этом участке кода мы перемещаем персонажа по осям x и z, а метод move_and_slide() применяет все наши изменения к velocity.

Отлично, мы завершили настройку передвижения. Теперь осталось добавить контроллер для мыши:

-10

  1. Объявляем перменные head, camera и sensitivity, для управления камерой.
  2. _unhandled_input(event) будет вызываться самостоятельно, для обработки всех ранее неперехваченных вводов.
  3. if event is InputEventMouseMotion: - Это условие проверяет, является ли событие, которое произошло, событием движения мыши.
  4. head.rotate_y(-event.relative.x * sensitivity) здесь мы поворачиваем ту самую голову персонажа вокруг оси Y.
  5. camera.rotate_x(-event.relative.y * sensitivity) поворачиваем камеру персонажа для избежания багов.
  6. camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-90), deg_to_rad(90)) - Эта строка ограничивает угол обзора камеры в пределах от -90 градусов до 90 градусов, что предотвращает переворачивание камеры.
  7. Всё работает, но теперь нам нужно скрыть курсор. Для этого добавим следующую строку в функцию _ready(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

Из-за введения вращения камеры, нам следует внести изменения в скрипт передвижения:

-11

Здесь мы добавили "head" к transform.basis, поскольку мы вращаем именно его, а не CharacterBody3D.

Отлично! Сегодня мы сделали большой шаг в разработке нашей игры, создав персонажа и настроив для него mouse и movement controller. , Следующие статьи предоставят нам возможность погрузиться в такие механики, как crouch, slide, run и stamina. Желаем вам удачи в вашем творчестве и разработке игры!