Добавить в корзинуПозвонить
Найти в Дзене

Создание игры для Android с использованием Godot (шаг 2)

Дать игроку понятную точку входа после запуска приложения и базовый контроль над громкостью до появления полноценного игрового поля, чтобы звуковые дорожки из будущих шагов можно было сразу направлять на правильные аудиошины. Ниже — практическое руководство по тому, как устроено решение второго пункта плана и как воспроизвести подход в собственном учебном проекте на Godot 4.x. Предполагается, что базовый каркас из первого шага уже есть: каталог `src/` открывается как корень проекта, главная сцена указана в `project.godot`. Чтобы не менять исторический путь главной сцены из шага 1, корневой узел **`Main`** остаётся узлом типа `Node`, а на него как дочерний экземпляр подцепляется сцена **`title_screen.tscn`**. Такой приём распространён, когда точку входа хотят держать «тонкой»: позже в `Main` можно добавить загрузчик сохранений, сессионную телеметрию или переключение между высокоуровневыми состояниями приложения без переписывания всего дерева интерфейса. Поток пользователя выглядит так:
Оглавление

2. Начальный экран и настройки звука

Цель

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

Описание выполненной работы

Ниже — практическое руководство по тому, как устроено решение второго пункта плана и как воспроизвести подход в собственном учебном проекте на Godot 4.x. Предполагается, что базовый каркас из первого шага уже есть: каталог `src/` открывается как корень проекта, главная сцена указана в `project.godot`.

Общая идея архитектуры экранов

Чтобы не менять исторический путь главной сцены из шага 1, корневой узел **`Main`** остаётся узлом типа `Node`, а на него как дочерний экземпляр подцепляется сцена **`title_screen.tscn`**. Такой приём распространён, когда точку входа хотят держать «тонкой»: позже в `Main` можно добавить загрузчик сохранений, сессионную телеметрию или переключение между высокоуровневыми состояниями приложения без переписывания всего дерева интерфейса.

Поток пользователя выглядит так:

1. Запуск → `main.tscn` → виден интерфейс меню из `title_screen.tscn`.

2. Кнопка «Играть» переводит игрока на сцену игрового поля **`game_board.tscn`** (шаг 3 плана).

3. Кнопка «Звук» открывает панель поверх интерфейса (слой `CanvasLayer`), где два горизонтальных ползунка управляют отдельными шинами микшера.

4. На Android кнопка «Выход» скрыта — там завершением приложения обычно управляет системная жестовая навигация.

Это позволяет параллельно разрабатывать игровую логику и UX оболочку: меню уже живёт своей жизнью и не блокируется заготовкой под поле.

Разметка меню без отдельной темы оформления

Экран построен на стандартных элементах Control‑ветки сцены: корневой `Control` растянут на весь видимый прямоугольник через пресет якорей «полный прямоугольник», поверх лежит `ColorRect` с тёмным космическим цветом близким к палитре постов репозитория. По центру расположен `CenterContainer`, который выравнивает вертикальный `VBoxContainer` с заголовком, подзаголовком и кнопками. Такой стек прост для начинающего: не нужны отдельные `Theme`‑ресурсы, чтобы получить аккуратное вертикальное меню на телефоне портретной ориентации.

Размеры кнопок заданы через `custom_minimum_size` по горизонтали порядка трёхсот двадцати пикселей и высотой около пятидесяти — это комфортная «мышечная память» для пальца на среднем смартфоне. Шрифт подтягивается системный через переопределение только числового размера (`theme_override_font_sizes/font_size`), что сохраняет читаемость без подключения собственных TTF до появления финального арта.

Если позже понадобится стилизация под нарисованную мультипликацию из описания игры, достаточно будет добавить `Theme` или заменить кнопки на текстуры «NinePatch», не меняя логики скриптов.

Панель настроек поверх основного интерфейса

Типичная ошибка новичка — вкладывать модальное окно прямо внутрь вертикальной колонки меню: при этом ломается центровка или элемент «уплывает» при смене языка текста. Здесь панель лежит в **`CanvasLayer`** с номером слоя выше основного интерфейса. У самого слоя координаты независимы от масштабирования корневого `Control`, а положение панели задаётся через якоря «центр экрана» и симметричные отступы.

В качестве контейнера выбран `PanelContainer`: он даёт рамку и отступ под контент через вложенный `MarginContainer`. Внутри вертикальный ряд подписей и двух строк с ползунками. Каждая строка — это `HBoxContainer`, где подпись имеет фиксированную минимальную ширину, а `HSlider` получает флаг растягивания по горизонтали и занимает всё оставшееся место.

Такое разбиение упрощает локализацию: когда строки станут длиннее на другом языке, ползунок автоматически сожмётся, но останется на одной линии с текстом.

Аудиошины Music и SFX без ручного редактирования ресурса микшера

Вместо того чтобы первым делом экспортировать `default_bus_layout.tres` из редактора, введён автозагрузочный узел **`GameAudio`**, который при старте проверяет наличие шин с именами `Music` и `SFX` и при необходимости создаёт их через API **`AudioServer`**. Обе шины посылают сигнал на **`Master`**, что соответствует привычной иерархии: итоговый уровень можно будет дополнительно регулировать системными кнопками громкости телефона.

Почему это удобно для учебного проекта:

- не нужно синхронизировать текстовый `.tres` микшера между версиями Godot при каждом изменении редактора;

- код явно документирует намерение («мы рассчитываем ровно на две дополнительные шины»);

- при первом запуске на чистой машине поведение одинаково предсказуемо.

Когда команда подключит реальные источники звука, достаточно в инспекторе для `AudioStreamPlayer` указать свойство **`bus`** равным `Music` или `SFX`, и ползунки начнут работать без дополнительных правок меню.

### Линейная шкала от нуля до единицы и перевод в децибелы

Человеку проще настраивать громкость на привычной шкале «тишина — максимум», поэтому ползунки работают в диапазоне **`[0; 1]`**. Внутри singleton линейное значение переводится в децибелы функцией движка **`linear_to_db`**. Для нуля линейной громкости вместо минус бесконечности используется практический пол — **`−80 dB`**, что на слух воспринимается как полное отсутствие сигнала и не порождает численных артефактов в дальнейших вычислениях.

Обратное чтение для инициализации ползунков идёт через **`get_bus_volume_db`** с проверкой на «почти тишину» и преобразование **`db_to_linear`**. Таким образом, одна и та же математика используется при загрузке сохранённых настроек и при ручном движении слайдеров, и UI не расходится с реальным состоянием микшера.

Сохранение в `user://` через `ConfigFile`

Персистентность реализована малым числом строк: выбран класс **`ConfigFile`**, который сериализует пары ключ–значение в каталог пользовательских данных движка. Путь **`user://audio_settings.cfg`** на десктопе и Android отображается в разные физические директории, но код остаётся кроссплатформенным.

В файл кладутся два ключа — нормализованные линейные громкости для шин `Music` и `SFX`. Загрузка на старте singleton сначала пытается прочитать файл; если его нет (первый запуск), подставляются разумные значения по умолчанию чуть ниже максимума, чтобы будущие клипы не «щёлкали» на полной громкости.

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

Автозагрузка singleton в `project.godot`

Чтобы `GameAudio` существовал раньше любой сцены, в проект добавлена секция **`[autoload]`** с записью вида **`GameAudio="*res://autoload/game_audio.gd"`**. Звёздочка перед путём — штатный синтаксис Godot для одиночного скрипта без оборачивания в отдельную сцену.

Порядок автозагрузок важен, если позже появятся зависимости между сервисами: здесь singleton один, конфликтов нет. Если в вашей ветке проекта активирован модуль **Mono**, GDScript‑автозагрузки продолжают работать параллельно с C# — это облегчает постепенное введение управляемого кода без полной переделки инфраструктуры.

Кнопка «Играть» вызывает **`get_tree().change_scene_to_file("res://scenes/game_placeholder.tscn")`**. Такой метод заменяет текущее дерево сцен целиком: узел `Main` исчезает до следующего возврата. Это сознательный компромисс для заглушки: когда игровое поле станет полноценным, можно будет заменить только строку пути или перейти на паттерн с верхнеуровневым менеджером сцен и предзагрузкой ресурсов.

Кнопка «Назад» из заглушки снова загружает **`main.tscn`**, восстанавливая меню вместе со вложенным экраном заголовка. На этом этапе не используется стек истории навроде **`push_scene`**, чтобы не усложнять код до появления реальной игровой петли.

Ограничения текущего шага и логичное продолжение в шаге 3

Меню уже задаёт эстетический тон тёмным фоном и светлыми подписями, но сознательно не реализует анимированный звёздный фон из текстового описания — это задача художественного оформления и может потребовать шейдера или многослойного параллакса. Аналогично, музыкальное сопровождение и звуки нажатий пока отсутствуют: важнее заложить правильную маршрутизацию по шинам.

Когда появится игровое поле, имеет смысл вынести общие цвета в `Theme`, подключить локализацию строк меню через CSV и, при необходимости, заменить прямое `change_scene_to_file` на сигналы верхнего контроллера, если понадобится плавная смена экранов с кросс‑фейдом.

Для самопроверки после правок рекомендуется сценарий: запустить проект в редакторе, открыть панель звука, убедиться, что ползунки двигаются плавно, перезапустить игру и убедиться, что значения восстановились из `user://audio_settings.cfg`. На устройстве Android стоит дополнительно проверить, что клавиша «Назад» системы ведёт себя ожидаемо — при необходимости следующие шаги добавят переопределение **`NOTIFICATION_WM_GO_BACK_REQUEST`**, если нужно перехватывать аппаратную или программную кнопку «назад».

Ссылка на статью: https://lets-go-code.ru/posts/godot/02-title-screen-audio/

Ссылка на проект: https://github.com/zz4567go/third-planet

Ссылка на игру: https://play.google.com/store/apps/details?id=ru.svp.tretiya_planeta.game