С вами
Дмитрий Горин, ментор по Godot
- Разработчик графических подсистем в АТОМ и инди-разработчик игр
- Участвую экспертом в мероприятиях и хакатонах, посвященных разработке игр
- Веду образовательную деятельность при университете РГРТУ им. В.Ф. Уткина (группа ВК)
Рад, что вы приступаете к разработке прототипа шутера на интенсиве Практик•ON. Удачи вам на этом пути! Вступить в чат Практик•ON для прохождения интенсива можно по ссылке: https://t.me/+gthG03srlcFlMzky. Вопросы по движку и программе можно задавать в соответствующем топике Godot чата Практик•ON.
Тема обозначена в названии статьи, так что приступаем.
Godot представляет собой легковесный, не требующий установки игровой движок с возможностью использовать не только встроенный Python-подобный GDscript, но и C#. Проект на Godot представляет из себя совокупность «сцен», кода, ресурсов (таких как спрайты, модели, звуки и т. п.) и файлы импорта для этих ресурсов. По этой причине проекты занимают мало места и работает всё крайне быстро на довольно слабом железе. Скачать актуальную версию движка можно по ссылке. На момент написания этого урока последней версией является 4.5.
После скачивания и распаковки архива можно приступать к работе. Открываете exe файл движка, и перед вами предстает менеджер проектов (рис. 1).
Рис. 1. Менеджер проектов.
По умолчанию проектов, конечно же, нет. Можно попробовать посмотреть проекты из библиотеки ассетов, но это не будет рассматриваться в рамках этого курса. Для создания своего проекта достаточно нажать на кнопку “Новый проект” и у вас откроются первоначальные настройки (рис. 2). Напишите название проекта (на английском), нажмите “Создать проект”, выберите режим отрисовки “Совместимость”. В пункте “метаданные контроля версий” выберите “Git”, если вы его знаете и используете, или “Пусто”, если не используете.
Рис. 2. Окно создания нового проекта.
Как только настройка готова, нажмите “Создать и редактировать”.
Перед вами предстает интерфейс движка с пустым проектом (рис.3).
Рис.3. Интерфейс игрового движка.
Интерфейс программы прост и не перегружен:
Игровая сцена и объекты на ней представляют дерево взаимосвязанных узлов, которые предоставляют отдельные функции, возможности для ваших объектов. Каждый узел на сцене можно настраивать и программировать. Для наглядности, давайте рассмотрим это на примере создания персонажа в мире будущей игры.
Для начала необходимо создать корневой узел игровой сцены. Обычно это стандартный узел – Node3D. Для его создания достаточно нажать в окне сцены “3D сцена” (рис. 4).
Рис. 4. Выбор корневого узла.
После этого у вас создастся узел Node3D и основное окно переключится в режим 3D. Можно сразу же переименовать узел в “Scene”, дважды кликнув по имени.
Зажав центральную кнопку (колесо) мыши, можно покрутить камеру вьюпорта вокруг созданной основы мира, но на этом возможности не ограничиваются! Покрутив колесо, меняется приближение камеры, а при зажатом Shift, вместо перемещения камеры вокруг, вы получите перемещения камеры влево-вправо и вверх-вниз.
Если вам и этого мало, то на зажатой правой кнопке мыши (ПКМ) вы поворачиваете камеру вьюпорта от её точки расположения, и в этот момент можно перемещаться как в игре, с помощью WASD клавиш. Если не устраивает скорость перемещения, она регулируется вращением колеса мыши.
Наигравшись с камерой вьюпорта, добавьте следующий узел, который будет корневым для персонажа – CharacterBody3D. Его переименуем в “Player”. Узел “Player” называется дочерним для “Scene”.
Как было написано ранее, каждый узел выполняет какой-то функционал, и CharacterBody3D специально существует для физических тел, управляемых пользователем. Вы увидите у узла “Player” предупреждение, что требуется дополнительный узел (рис. 5).
Рис. 5. Предупреждение узла.
Решение описано в предупреждении – добавляем CollisionShape3D как дочерний узел для “Player”. С помощью него мы можем задать форму тела будущего героя. У этого узла также будет предупреждение, что форма не задана. Выберите узел CapsuleShape3D и справа, в “Инспекторе” задайте прямоугольную форму CapsuleShape3D (рис. 6).
Рис. 6. Создание формы у героя.
Предупреждение пропадет. При повторном нажатии на уже созданный ресурс формы, появятся дополнительно параметры уже самой формы (рис. 7).
Рис. 7. Редактирование формы.
Капсула считается стандартом для коллизии персонажей в современных игровых движках:
Теперь можно дать и некоторую внешность нашему персонажу, добавив “Player” дочерний узел MeshInstance3D. Пока пусть вид будет соответствовать форме: обычная капсула. В инспекторе у MeshInstance3D можете создать меш – полигональную сетку, описывающую 3D модель (рис. 8).
Рис. 8. Создание меша для модели.
Чтобы положение нашего персонажа считалось относительно не центра капсулы, а с низа, условных ног, стоит перенести повыше CollisionShape3D и MeshInstance3D. Если вы не меняли настройки капсул в них, то поднять на 1 вверх, т.е. потянуть по оси Y за зеленую стрелочку вверх. Можно выделить одновременно 2 объекта, зажав Ctrl, и перетащить их. Для привязки к сетке при перемещении, можно зажать Ctrl для точного установленного значения, либо установите в Инспекторе свойство “Transform → Position → y” в 1.0 (аним. 1).
Аним. 1. Расположение коллизии и меша игрока.
Был сделан заметный прогресс, который не хочется бесследно потерять. Сохраните созданную игровую сцену, выбрав сверху экрана “Сцена → Сохранить сцену”, или комбинацией Ctrl + S. По умолчанию название сохраняемой сцены берется из названия корневого узла. Я назову “TestScene”. Кидаем прямо в корень папки проекта, не стесняемся. Потом там приберемся.
Для удобства выделения и перемещения нашего персонажа во вьюпорте с помощью мыши, его можно сгруппировать. Для этого выберите узел, чьи дочерние узлы будут сгруппированы (у нас это “Player”) и нажмите на иконку “сгруппировать” (рис. 9). У узла “Player” появится иконка.
Рис. 9. Группировка узлов.
Пусть наш 3D мир и будет крутиться вокруг игрока, но не состоять же только из него? Было бы неплохо добавить на игровую сцену другие объекты, и по хорошему, которые тоже имеют коллизию. Предлагаю добавить пол и кубик на этом полу, которые будут представлять из себя StaticBody3D. По отработанному на игроке сценарии собираем 2 объекта этого типа: “Wall” и “Cube” (рис. 10). Нет смысла делать полноценный огромный мир на этом этапе.
Рис. 10. Простая сцена с 3-мя объектами.
Данная сцена уже выглядит достаточно интересно, чтобы её запустить. Но не тут-то было…
Если вы запустите вашу заготовленную сцену, то увидите лишь серую пустоту. Чтобы увидеть прекрасный и жизнерадостный мир, требуется транслятор 3D мира на наши плоские экраны – Camera3D!
Можно добавить камеру на сцену, закрепив её на игрока. В инспекторе вы увидите, что в эту камеру видно. Поставим её на уровне глаз, повыше, и поставим куб в области видимости камеры (рис. 11).
Рис. 11. Установка камеры на персонажа.
Не торопитесь запускать. Пусть вам и показывают солнечный погожий день во вьюпорте и камере – это всё демоверсия предпросмотр. Если отключите кнопки предпросмотра окружения и света, увидите реальную картину (рис. 12).
Рис. 12. Выключенный предпросмотр освещения и окружения.
Добавьте собственное окружение WorldEnvironment на сцену и настройте фоновые облака (рис. 13).
Рис. 13. Стандартный сгенерированный фон неба.
Добавьте направленный свет DirectionalLight3D. Этот тип освещения светит на весь мир и в одном направлении, которое рекомендую вам настроить инструментами вращения во вьюпорте. Можете и переместить положение этого узла, но это ни на что не влияет в отображении (рис. 14). Не забудьте включить тени в Инспекторе в “Light3D → Shadows”.
Рис. 14. Настроенный свет и освещение.
Запустите проект, нажав на соответствующую кнопку в правой верхней части интерфейса. Если это будет первый запуск, вам предложат выбрать, какую сцену запустить. Выбираете текущую, и произойдет запуск проекта. Наконец, свет отражается от наших объектов и попадает прямо к нам в камеру (рис. 15).
Рис. 15. Запущенная игровая сцена
Теперь, когда сцена настроена, самое время переходить к её программированию!
Для программирования на движке Godot можно использовать GDScript, C# и С++, но самый надежный вариант - использовать GDScript, являющийся языком программирования по умолчанию и разработанным специально для этого движка. Этот язык использует синтаксис, похожий на Python, но со своими особенностями. Для ознакомления с основами языка, особенно если вы программировали ранее на каком-либо из языков, рекомендую посмотреть основы языка GDScript из документации. Не обязательно знать всё из здесь перечисленного. Для начала будет достаточно знать: переменные, константы, условия, циклы и функции. Будет так же не лишним ознакомиться с руководством по стилю кода, принятому в GDScript.
Для демонстрации программирования на движке, сделаем управление по клавишам для нашего персонажа и движение камеры мышью. Для этого выберем наш узел “Player” на сцене и “ПКМ → Прикрепить скрипт”. Появится окно создания скрипта (рис. 16).
Рис. 16. Окно создание скрипта
Нажимаете создать, и на основном окне движка вы перемещаетесь во вкладку “Scripts” с частично написанным кодом:
Pythonextends CharacterBody3D
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()Пояснения к коду:
При написании кода учитывайте, что отступы крайне важны и сделаны исключительно с помощью табуляции.
Кода выше достаточно для перемещения героя, но не для управления камерой. Вы можете запустить проект, но без привычного управления мышью крайне неудобно. Исправим это, добавив между константами и функцией следующий код:
Pythonconst MOUSE_SENSITIVITY = 0.002
@onready var camera: Camera3D = $Camera3D
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
rotate_y(-event.relative.x * MOUSE_SENSITIVITY)
camera.rotation.x = clamp(camera.rotation.x - event.relative.y * MOUSE_SENSITIVITY, -PI / 2, PI / 2)Пояснения к коду:
Благодаря этому коду вы получите привычное управление для 3D игр с видом от первого лица.
P.S. Это вас пока не коснется, но почитайте на досуге про проблемы углов Эйлера. Когда вы с ними встретитесь, решение уже будет у вас наготове.
Действия ввода (input actions) – это совокупность входных сигналов, будь это нажатие клавиши клавиатуры, мыши или даже игрового контроллера, объединенных под одним названием. Таким образом вы можете настраивать управление в вашей игре, а также менять его в процессе игры и мгновенно добавлять управление с геймпада, и не только. Для того, чтобы посмотреть список действий, необходимо перейти в меню «Проект → Настройки проекта… → Список действий → Показать встроенные действия», и перед вами окажется список, который вы можете редактировать под себя (рис. 17).
Рис. 17. Список действий
Заметьте, что название действия в функцию передается в двойных кавычках, то есть это строковый тип данных.
Если всё сделано правильно, можно сохранить код, сцену, и запустить проект, нажав на соответствующую кнопку в правой верхней части интерфейса. В нём вы сможете перемещать вашего персонажа в 4 стороны по нажатию стрелок (если не меняли “действия”), совершать прыжок и перемещение камеры мышью.