Для создания столь простой игры нам понадобится совсем немного: движок и пара рук.
1. Установка движка и создание директории проекта
[1] Переходим на сайт Godot Engine и сразу тыкаем на большую синюю кнопку "Godot Engine - 4.0.1" (если вы пользователь Windows, в ином случае придется опуститься чуть ниже, до раздела "Supported platforms" и выбрать там уже подходящую вам систему).
На выходе получим архив, из которого и нужно достать .exe-файл движка (в моем случае: "Godot_v4.0.1-stable_win64.exe"). Запускаем Godot.
В правом верхнем углу окна можно выбрать нужный язык. Интерфейс движка переведен и на русский. Но я обычно использую английский.
[2] Нажимаем "создать новый проект/+ New Project", выбираем название директории проекта и путь до самой папки. (Нажмите "создать папку/create folder", если вы выбрали путь к еще не существующей директории).
Остальные настройки оставляем как есть. Жмем "создать и редактировать/create & edit" - готово! Ваш проект создан: новенький, девственный и абсолютно пустой. Скоро исправим.
Остальные настройки оставляем как есть. Жмем "создать и редактировать/create & edit" - готово! Ваш проект создан: новенький, девственный и абсолютно пустой. Скоро исправим.
2. Знакомство с интерфейсом
Перед нами предстает интерфейс движка. Давайте разбереv его базовые элементы на рисунке ниже.
- Базовые вкладки программы. Позволяют сохранить текущий проект, создать новый, изменить базовые настройки редактора/режима отладки, посмотреть справку по работе в движке и т.д.
- Панель редакторов. 2D-редактор нужен для работы с двумерными играми и 2D-элементами трехмерных приложений. 3D-редактор нужен для работы с трехмерными играми. Script-редактор - для написания кода соответственно. AssetLib - переместит вас на окно скачивания готовых наработок движка, которые опубликовали другие пользователи.
- Панель для запуска проекта/определенной сцены игры в тестовом режиме
- Выбор рендерера. Можно установить при создании проекта или через данную кнопку. Позволяет выбирать пресеты для работы с графикой более мощной, но только под настольные платформы (Forward+) или меньшие мощности, которые можно будет запустить и на мобильных устройствах (Mobile)
- Вкладки текущей сцены/добавление новой. Сцены - это основополагающий элемент игр/программ, созданных в Godot. Работа с ними будет разобрана более подробно далее.
- Окно редактора нодов/node текущей сцены. Здесь имеются две вкладки: "сцена/scene" - отображает древо нодов текущей сцены; "импорт/import" - позволяет выбрать настройки импортируемых изображений/моделей/музыки. Об этом позже.
- Панель инструментов. Позволяет производить манипуляция с объектами в 2D/3D-редакторах: перемещать, вращать, масштабировать объекты и т.д.
- Рабочая область. Собственно окно, в котором и будут происходить все манипуляции с объектами на сцене.
- Окно инспектора. Здесь три вкладки: "инспектор/inspector" - отображает все поля атрибутов выбранного нода/node; "Ноды/node" - отображает перечень доступных "сигналов" (о них расскажем позже) нодов, а также позволяет назначить ноде группу; "История изменений/History" - отображение всех изменений текущего нода в хронологическом порядке с возможностью вернуться к любому из них.
- Проводник. Отображение всех папок и файлов в директории проекта.
- Панель отладки. "Вывод/Output" отображает информацию, выводимую в консоль; "Отладка/debug" предоставляет детальную информацию в ходе исполнения кода программы; "Аудио/Audio" - простой микшер аудио-файлов; "Анимация/Animation" - редактор анимаций (подробнее будет рассмотрен позже); "Редактор шейдеров/Shader editor" - позволяет создавать шейдеры в стандартном кодовом виде или путем работы с графическими блоками.
3. Создаем первую сцену
[1] Идем в окнов редактора нодов, он пока что пуст и редактор напоминает нам "создать корневой нод/create root node". Так как игру мы планируем делать трехмерную, то выбираем пункт "3D-сцена/3D-Scene" - будет добавлен нод "Node3D", самый базовый для трехмерных объектов. Либо вместо этого можно нажать на значок "+" в выбрать тот же "Node3D" в выпадающем списке.
А что вообще такое эти ноды? Ноды, это как бы экземпляры классов определенных объектов. К примеру, "Node3D" основной нод трехмерных объектов, содержит в себе матрицу Transform3D, а также параметры видимости объекта. Все прочие ноды для работы в 3D, наследуются от Node3D.
Первый нод добавлен. Дважды по нему щелкаем и переименовываем в Main. Сохраняемся: Ctrl + S. В новом окне создадим отдельную директорию под наши сцены: правая кнопка мыши -> "Новая папка/New Folder", назовем ее "Scenes". И уже в нее сохраняем нашу первую сцену; разрешение файла будет .tscn
[2] Первая сцена готова, но она пустая. Далее нам потребуется космический корабль, которым и будет управлять игрок. Создадим для этого новую сцену: справа от вкладки текущей сцены нажимаем на кнопку "+", откроется окно с новой пустой спецой. В редакторе нодов выберем пункт "Другие ноды/Other Node"; в новом окне в графе поиска начните писать "character" и в окне новод останется только два пункта: "CharacterBody2D" и "CharacterBody3D". Нам нужен последний - добавляем. Переименовываем его в "Player". Сохраняем сцену. Давайте создадим в папке "Scenes" подпапку "Units", куда и сохраним нашу сцену "player.tscn"
CharacterBody3D - нод для обработки физики движущихся тел. В нем уже содержаться необходимые методы для обработки столкновений с другими объектами, чем мы в дальнейшем и воспользуемся.
[3] Нашему кораблю нужна модель, уж больно сложно восприниматься игру без графики. Вы, конечно, можете найти и использовать свои модели, но для целей данной статьи я уже подготовил вам архив с нужными материалами. Скачиваем его. Далее переходим в проводник редактора, нажимаем правую кнопку мыши, выбираем пункт "Открыть в проводнике/Open in File Manager" - появится папка проекта, в нее и распаковываем содержимое архива. Возвращаемся в Godot и редактор сам подгрузит все новые файлы.
Теперь файлы проекта должны выглядеть как на картинке справа.
Возвращаемся в редактор нодов, выбираем нод Player, и нажимаем на "+" (или Ctrl + A), чтобы добавить "игроку" дочерний нод. Ищем "MeshInstance3D", добавляем, по желанию можно сменить его название на "Model"
Возвращаемся в редактор нодов, выбираем нод Player, и нажимаем на "+" (или Ctrl + A), чтобы добавить "игроку" дочерний нод. Ищем "MeshInstance3D", добавляем, по желанию можно сменить его название на "Model"
Как и следует из названия "MeshInstance3D" нужен для отображения меша 3D модели или заготовленных примитивов.
Теперь выберем "Model" (тип MeshInstance3D) и в инспекторе справа найдем поле "Mesh" (первое по списку), у которого стоит значение <empty>. Перетащим сюда нашу модель: идем в проводник и по пути "Assets/mdl" находим файл "Spaceship_RaeTheRedPanda.obj", и просто перетягиваем его на поле "Mesh". Наша модель отобразиться в рабочей области. Все замечательно, но есть два "Но". Модель белая, у нее нет текстуры и модель повернута "лицом" к игроку, а вид в игре планируется сзади.
[4] Приступим к настройке модели. Если мы рассмотрим расположение элементов в инспекторе, то заметим, что все поля разделены на разделы: сверху MeshInstance3D и его поля, далее GeometryInstance3D, VisualInstance3D и Node3D - все расположено в порядке наследования. Перейдем в раздел Node3D инспектора, вкладка Transform, здесь зададим значение полю Rotation, вернее элементу Y, равным "180". Теперь модель повернута в нужное направление.
Займемся текстурой. Находим файл "Atlas.png" по пути "Assets/mdl" и перетаскиваем его на нашу модель космического корабля. Теперь в инспекторе в разделе "GeometryInstance3D" во вкладке "Geometry" будет добавлен новый стандартный материал с нашей текстурой. Для наших целей хватит.
Займемся текстурой. Находим файл "Atlas.png" по пути "Assets/mdl" и перетаскиваем его на нашу модель космического корабля. Теперь в инспекторе в разделе "GeometryInstance3D" во вкладке "Geometry" будет добавлен новый стандартный материал с нашей текстурой. Для наших целей хватит.
[5] Теперь настроим управление для нашего корабля. Вновь выбираем нод "Player" и в правом верхнем углу редактора нодов нажимаем на кнопку с иконкой свитка "добавить новый или существующий скрипт к ноду". В новом окне можно все оставить по умолчанию, нажимайте "ОК". Будет создан скрипт "player.gd" и вас переместит в редактор скриптов.
Писать код в данной статье мы будет на GDScript, собственный скриптовый язык движка Godot, который по своему синтаксису похож на Python.
В новом скрипте будет добавлен код из шаблона для базового движения 3D-объекта. Удалим все кроме первой строчки и напишем следующее:
Писать код в данной статье мы будет на GDScript, собственный скриптовый язык движка Godot, который по своему синтаксису похож на Python.
В новом скрипте будет добавлен код из шаблона для базового движения 3D-объекта. Удалим все кроме первой строчки и напишем следующее:
Первая строка остается как есть
extends CharacterBody3D
Ключевое слово "extends" используется для объявления наследования, в данном случае от класса CharacterBody3D. В скрипте нода может быть объявлено только одного наследование от одного класса.
const SPEED = 40.0
const ACCELERATION = 1.5
const SCREEN_BORDER = Vector2(15.0, 10.0)
const ROTATION_LIMIT = 55.0
Ключевое слово "const" используется для объявления константы
var direction = Vector3.ZERO
var - используется для объявления переменной; в GDScript тип переменных определяется динамически
Впрочем тип переменных можно указывать и явно. Для этого после имени переменной нужно поставить двоеточие ":" и название типа.
Например: "var direction : Vector3 = Vector3.ZERO". Еще есть вариант с автоматическим указанием типа по заданному значению: "var direction := Vector3.ZERO". Явно указание типа переменных отлично помогает, когда проект разрастается в масштабе, ведь редактор сразу выдаст ошибку, если вы попытаетесь назначить переменной не тот тип данных. Но в данной статье мы этим пользоваться не будем.
Впрочем тип переменных можно указывать и явно. Для этого после имени переменной нужно поставить двоеточие ":" и название типа.
Например: "var direction : Vector3 = Vector3.ZERO". Еще есть вариант с автоматическим указанием типа по заданному значению: "var direction := Vector3.ZERO". Явно указание типа переменных отлично помогает, когда проект разрастается в масштабе, ведь редактор сразу выдаст ошибку, если вы попытаетесь назначить переменной не тот тип данных. Но в данной статье мы этим пользоваться не будем.
func _process(delta):
direction = Input.get_vector("ui_left", "ui_right", "ui_down", "ui_up")
transform.origin.x = clamp(transform.origin.x, -SCREEN_BORDER.x, SCREEN_BORDER.x)
transform.origin.y = clamp(transform.origin.y, -SCREEN_BORDER.y, SCREEN_BORDER.y)
rotation_degrees.z = clamp(velocity.x * -1.5, -ROTATION_LIMIT, ROTATION_LIMIT)
func - используется для объявления функции. _process(delta) - стандартная функция, которая есть у любого объекта; вызывается каждый кадр.
Получаем нормализированный вектор направления при помощи функции Input.get_vector. "ui_left", "ui_right", "ui_down", "ui_up" - названия стандартных "действий" движка (нажатие на стрелки клавиатуры) Чуть позже мы посмотрим, как их настроить. Далее мы ограничиваем перемещение корабля, чтобы он не улетал за пределы экрана и наклоняем объект при движении из стороны в сторону.
Получаем нормализированный вектор направления при помощи функции Input.get_vector. "ui_left", "ui_right", "ui_down", "ui_up" - названия стандартных "действий" движка (нажатие на стрелки клавиатуры) Чуть позже мы посмотрим, как их настроить. Далее мы ограничиваем перемещение корабля, чтобы он не улетал за пределы экрана и наклоняем объект при движении из стороны в сторону.
func _physics_process(delta):
velocity.x = move_toward(velocity.x, direction.x*SPEED, ACCELERATION)
velocity.y = move_toward(velocity.y, direction.y*SPEED, ACCELERATION)
move_and_slide()
# теперь осталось только вызвать функцию
_physics_process(delta) - еще одна стандартная функция любого объекта в движке. Также вызывается каждый кадр. В отличие от _process(delta) следует использовать только для просчета физических процессов.
Вектор движения velocity уже является внутренним компонентом CharacterBody3D. Нам нужно только задать ему значение direction*SPEED. а функция move_toward поможет сделать набор скорости плавным. И под конец вызываем функцию move_and_slide(), она переместит объект в соответствии с вектором двмжения velocity и просчитает все коллизии.
Вектор движения velocity уже является внутренним компонентом CharacterBody3D. Нам нужно только задать ему значение direction*SPEED. а функция move_toward поможет сделать набор скорости плавным. И под конец вызываем функцию move_and_slide(), она переместит объект в соответствии с вектором двмжения velocity и просчитает все коллизии.
player.gd [весь код целиком]
extends CharacterBody3D
const SPEED = 40.0
const ACCELERATION = 1.5
const SCREEN_BORDER = Vector2(15.0, 10.0)
const ROTATION_LIMIT = 55.0
var direction = Vector3.ZERO
func _process(delta):
direction = Input.get_vector("ui_left", "ui_right", "ui_down", "ui_up")
transform.origin.x = clamp(transform.origin.x, -SCREEN_BORDER.x, SCREEN_BORDER.x)
transform.origin.y = clamp(transform.origin.y, -SCREEN_BORDER.y, SCREEN_BORDER.y)
rotation_degrees.z = clamp(velocity.x * -1.5, -ROTATION_LIMIT, ROTATION_LIMIT)
func _physics_process(delta):
velocity.x = move_toward(velocity.x, direction.x*SPEED, ACCELERATION)
velocity.y = move_toward(velocity.y, direction.y*SPEED, ACCELERATION)
move_and_slide()
[6] Возвращаемся на сцену "Main". Добавляем нод "Camera3D", он позволит нам видеть, что вообще происходит на экране. Сдвинем ее чутка назад по оси Z: Инспектор/Node3D/Transform/Position.z = 9.
Теперь в редакторе нодов нажимаем на кнопку с иконкой цепи (рядом с "+") "добавить экземпляр дочерней сцены" и выбираем player.tscn. Либо же можно просто перетащить файл сцены "Player" из проводника в рабочую область. Изменим его Transform/Position на -4 по оси Y и -8 по оси Z (то есть чуть ниже и подальше от камеры).
Теперь в редакторе нодов нажимаем на кнопку с иконкой цепи (рядом с "+") "добавить экземпляр дочерней сцены" и выбираем player.tscn. Либо же можно просто перетащить файл сцены "Player" из проводника в рабочую область. Изменим его Transform/Position на -4 по оси Y и -8 по оси Z (то есть чуть ниже и подальше от камеры).
Добавим новый нод на сцену "DirectionalLight3D". В инспекторе ставим значение Light3D/Light/Energy = 1.5, а Transform/Rotation.X = -30;
Дублируем нод "DirectionalLight3D" (Ctrl + D) и в дубликате, ставим Energy = 0.5, а Rotation.X = 30
Дублируем нод "DirectionalLight3D" (Ctrl + D) и в дубликате, ставим Energy = 0.5, а Rotation.X = 30
Теперь, чтобы наш корабль не плыл в сером экране добавляем нод WorldEnvironment, идем в инспектор, поле Environment. Нажимаем на <empty> и выбираем "New Environment". Тем самым мы добавили в поле новый ресурс типа "environment". И тут не совсем очевидный момент. Теперь нажимаем на только что созданный ресурс и откроется контекстного меню, позволяющее сделать детальную настройку. Ищем Background/Mode и меняем значение с "Clear Color" на "Sky". Чуть ниже появится новая вкладка "Sky". Идем в нее, нажимаем на <empty> и выбираем "New Sky". добавится еще один новый ресурс, нажимаем на него и откроется контекстное меню с уже с настройками ресурса типа "Sky" (Привыкайте, в инспекторе будет попадаться много вложенных ресурсов). Нажимаем на <empty> в поле "Sky Material" и выбираем "New PanoramaSkyMaterial". Заходим в него и в поле "Panorama" перетаскиваем текстуру из проводника, находящуюся по пути "Assets/gfx/bg/environment.png".
Готово, теперь окружение имеет космический вид.
[7] Почти все готово для первого запуска. Дело осталось за малым. Настроим параметры запуска нашего приложения: идем в базовые вкладки программы Project -> Project Settings, в новом окне находим Aplication -> Run и напротив поля "Main scene" нажимаем на иконку папки. В новом окне находим нашу сцену "main.tscn". Подтверждаем. Мы установили главную сцену приложения, ту, которая и будет запускаться при старте программы.
Тут же в настройках Display -> Window можно задать размер экрана "viewport width", "viewport height". Для теста я поставил 960х540 (половина от FullHD)
Теперь в настройках переходим на вкладку "InputMap" и переключаем флажок "Show Build-In Actions" в положение Вкл. Находим "ui_left", нажинаем на плюсик справа и нажимаем на клавишу клавиатуры, которая будет также отвечать за данное действие, в нашем случае - "A". По аналогии назначаем "ui_right", "ui_up", "ui_down" значение D, W, S. Это чтобы можно было не только на стрелочках управлять кораблем.
Готово. Можно запускать и тестировать (F5).
Наш корабль бороздит просторы космоса! Пока еще статичного... И делать тут особо нечего.. Но мы это исправим в следующей главе!
Нажмите на кнопку "Получить" ниже, чтобы скачать архив с текущим состоянием проекта