Графический интерфейс

Заключительный этап нашей игры нуждается в Пользовательском интерфейсе (UI), чтобы отображать такие вещи, как очки, сообщение "игра окончена" и кнопку перезапуска.

Создайте новую, сцену нажмите на "Другой узел" и добавьте узел CanvasLayer с именем HUD. "HUD" означает "heads-up display", дисплей, отображающийся поверх игры.

Узел CanvasLayer позволяет нам прорисовывать элементы нашего UI на слое поверх всей остальной игры, поэтому отображаемая информация не перекрывается никакими игровыми элементами, такими как игрок или мобы.

HUD должен отображать следующую информацию:

  • Счет, измененный ScoreTimer.

  • Сообщение, например "Game Over" или "Get Ready!"

  • Кнопку "Start" для начинания игры.

Основной узел для элементов UI — это Control. Чтобы создать наш UI, мы будем использовать два типа узлов Control:, Label и Button.

Создайте следующие узлы, как дочерние узла HUD:

  • Label с именем ScoreLabel.

  • Label с именем Message.

  • Button с именем StartButton.

  • Timer с именем MessageTimer.

Нажмите на ScoreLabel и введите число в поле Text в Инспекторе. Стандартный шрифт для узлов Control мал и плохо масштабируется. В ресурсы игры включен файл шрифта под названием "Xolonium-Regular.ttf". Чтобы использовать этот шрифт, сделайте следующее:

В "Theme Overrides > Fonts" выберите "Загрузить" и выберите файл "Xolonium-Regular.ttf".

../../_images/custom_font_load_font.webp

Размер шрифта все еще слишком мал, увеличьте его до 64 в разделе «Theme Overrides > Font Sizes». Сделав это для ScoreLabel, повторите изменения для узлов Message и StartButton.

../../_images/custom_font_size.webp

Примечание

Якоря: Узлы Control имеют не только положение и размер, но также якоря. Якоря определяют начало координат - опорную точку для краев узла.

Расположите узлы, как показано ниже. Вы можете перетаскивать узлы, чтобы разместить их вручную, или для более точного размещения используйте "Предустановки значений для якорей и отступов узла Control".

../../_images/ui_anchor.webp

ScoreLabеl

  1. Установите текст на 0.

  2. В Инспекторе, установите "Horizontal Alignment" и "Vertical Alignment" на Center.

  3. Установите "Предустановки значений для якорей и отступов узла Control" на Вверху по центру.

Message

  1. Установите текст на Увернись от Крипов!.

  2. В Инспекторе, установите "Horizontal Alignment" и "Vertical Alignment" на Center.

  3. Установите "Autowrap Mode" на Word, в противном случае надпись останется на одной строке.

  4. В разделе "Control - Layout/Transform" установите для параметра «Size X» значение на``480``, чтобы использовать всю ширину экрана.

  5. Установите "Предустановки значений для якорей и отступов узла Control" на По центру.

StartButtоn

  1. Установите текст на Старт.

  2. В разделе "Control - Layout/Transform" установите для параметра «Size X» значение 200, а для параметра "Size Y" значение 100, чтобы добавить немного больше отступа между границей экрана и текстом.

  3. Установите "Предустановки значений для якорей и отступов узла Control" на Внизу по центру.

  4. В разделе "Control - Layout/Transform" установите для параметра "Position Y" значение 580.

В MessageTimer установите параметр Wait Time на 2, а параметр One Shot на значение "Вкл".

Теперь добавьте этот скрипт в HUD:

extends CanvasLayer

# Notifies `Main` node that the button has been pressed
signal start_game

Теперь мы хотим временно отобразить сообщение, например "Get Ready" (Приготовьтесь), поэтому мы добавляем следующий код

func show_message(text):
    $Message.text = text
    $Message.show()
    $MessageTimer.start()

Также нам нужна функция, которая будет вызываться, когда игрок проигрывает. Она покажет надпись "Game Over" на 2 секунды, затем произойдет возврат к основному экрану, и после короткой паузы появится кнопка "Старт".

func show_game_over():
    show_message("Game Over")
    # Wait until the MessageTimer has counted down.
    await $MessageTimer.timeout

    $Message.text = "Dodge the Creeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    await get_tree().create_timer(1.0).timeout
    $StartButton.show()

Примечание

Если вам нужно сделать паузу на короткое время, то альтернативой использованию узла Timer является использование функции SceneTree create_timer(). Может быть очень полезно добавлять задержки наподобие таких, как в вышеприведенном коде, где нам хотелось бы подождать немного времени, прежде чем показывать кнопку "Start".

Добавьте приведенный ниже код в HUD, чтобы обновлять счет

func update_score(score):
    $ScoreLabel.text = str(score)

Присоедините сигнал timeout() из MessageTimer и сигнал pressed() из StartButton к узлу HUD и добавьте следующий код к новым функциям:

func _on_start_button_pressed():
    $StartButton.hide()
    start_game.emit()

func _on_message_timer_timeout():
    $Message.hide()

Подключение HUD к Main

Теперь, когда мы закончили создание сцены HUD, вернитесь к Main. Инстанцируйте сцену HUD в Main подобно тому, как вы это делали со сценой Player. Дерево сцены должно выглядеть так, поэтому убедитесь, что вы ничего не упустили:

../../_images/completed_main_scene.webp

Теперь нам нужно подключить функционал HUD в наш Main-скрипт. Для этого потребуются некоторые дополнения к сцене Main:

Во вкладке Узел присоедините сигнал HUD start_game к функции узла Main new_game() и, нажав кнопку "Присоеденить" в окне "Присоединить сигнал к методу", выбрать метод new_game(). Убедитесь, что в скрипте рядом с функцией func new_game() теперь появилась зелёная иконка подключения.

В new_game() обновим отображение счёта и выведем сообщение "Get Ready":

$HUD.update_score(score)
$HUD.show_message("Get Ready")

В game_over() нам нужно вызвать соответствующую функцию HUD:

$HUD.show_game_over()

Наконец добавьте этот код в _on_score_timer_timeout(), чтобы синхронизировать отображение с изменением количества очков:

$HUD.update_score(score)

Предупреждение

Когда вы убедитесь, что всё работает, удалите вызов new_game() из _ready(), иначе ваша игра запустится автоматически.

Теперь вы готовы играть! Нажмите кнопку "Play the Project".

Удаляем старых крипов

Если вы играете до "Game Over", а затем сразу начинаете новую игру, то крипы из предыдущей игры могут все еще оставаться на экране. Было бы лучше, если бы все они исчезали в начале новой игры. Нам просто нужен способ сказать всем мобам, чтобы они удалились. Мы можем сделать это с помощью функции "group" ("группа").

In the Mob scene, select the root node and click the Groups tab next to the Signals tab and the "+" button to open the "Create New Group" dialog.

../../_images/group_tab.webp

Назовите группу mobs и нажмите «ok», чтобы добавить новую группу сцены.

../../_images/add_group_dialog.webp

Теперь все мобы будут в группе «mobs».

../../_images/scene_group_mobs.webp

Затем мы можем добавить следующую строку в функцию new_game() в Main:

get_tree().call_group("mobs", "queue_free")

Функция call_group() вызывает каждую именованную функцию на каждом узле в группе - в этом случае мы говорим каждому мобу удалять себя.

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