Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Головна сцена гри

Тепер настав час об'єднати все, що ми зробили, разом, в ігрову сцену.

Створіть нову сцену та додайте Node з ім'ям Main. (Ми використовуємо Node, а не Node2D, тому що саме цей вузол буде контейнером для обробки логіки гри. Він не вимагає 2D-функціональності.)

Клацніть кнопку Створити екземпляр дочірньої сцени (іконка ланцюжка) і виберіть збережений player.tscn.

../../_images/instance_scene.webp

Тепер додайте наступні вузли як дочірні вузли Main і назвіть їх, як показано:

  • Timer (названий MobTimer) - щоб контролювати, як часто виникають моби

  • Timer (названий ScoreTimer) - збільшуватиме рахунок щосекунди

  • Timer (названий StartTimer) - щоб дати затримку перед запуском

  • Marker2D (названий StartPosition) - для визначення стартової позиції гравця

Встановіть властивість Час очікування кожного з вузлів Таймер наступним чином (значення в секундах):

  • MobTimer: 0.5

  • ScoreTimer: 1

  • StartTimer: 2

Крім того, встановіть властивість One Shot в StartTimer на "включено" і задайте Position в StartPosition на (240, 450).

Поява мобів

Головний вузол породжуватиме нових мобів, і ми хочемо, щоб вони з'являлися у випадковому місці на краю екрана. Клацніть вузол Головний на панелі сцени, потім додайте дочірній вузол Path2D з назвою MobPath. Коли ви виберете Path2D, ви побачите кілька нових кнопок у верхній частині редактора:

../../_images/path2d_buttons.webp

Виберіть середню ("Додати точку") та намалюйте шлях, клацнувши, щоб додати точки у вказаних кутах. Щоб точки прикріпилися до сітки (ґратки), переконайтеся, що опції "Використати до ґратки" та "Використати прив'язку", обидві включені. Ці опції можна знайти зліва від кнопки «Блокування», виглядає як магніт з кількома лініями, що перетинаються.

../../_images/grid_snap_button.webp

Важливо

Малюйте доріжку за годинниковою стрілкою , інакше ваші моби будуть виникати спрямовані назовні, а не всередину!

../../_images/draw_path2d.gif

Після розміщення точки 4 на зображенні натисніть кнопку «Закрити криву», і ваша крива буде завершена.

Тепер, коли шлях визначений, додайте вузол PathFollow2D (слідувати за шляхом 2D) нащадком MobPath та назвіть його MobSpawnLocation. Цей вузол автоматично обертатиметься та рухатиметься по шляху, тому ми можемо використовувати його для вибору випадкової позиції та напрямку вздовж шляху.

Ваше сцена має виглядати так:

../../_images/main_scene_nodes.webp

Головний скрипт

Додайте скрипт до вузла Main. У верхній частині скрипту ми використовуємо @export var mob_scene: PackedScene, щоб ми могли вибрати сцену Mob, екземпляр якої ми хочемо створити.

extends Node

@export var mob_scene: PackedScene
var score

Натисніть вузол Main, і ви побачите властивість Mob Scene в інспекторі під "Main.gd".

Ви можете змінити значення цієї властивості двома шляхами:

  • Перетягнути mob.tscn з панелі "Файлова система" у властивість Mob Scene.

  • Клацнути стрілочку вниз поряд з "[empty]"(пусто) і вибрати "Load" (Завантажити). Виберіть mob.tscn.

Next, select the instance of the Player scene under Main node in the Scene dock, and access the Signals dock on the sidebar.

Ви повинні побачити список сигналів для вузла Гравець. Знайдіть і двічі клацніть сигнал hit у списку (або клацніть його правою кнопкою миші та виберіть «Підключити...»). Відкриється діалогове вікно підключення сигналу. Ми хочемо створити нову функцію під назвою game_over, яка оброблятиме те, що має статися після закінчення гри. Введіть «game_over» у полі «Метод приймача» внизу діалогового вікна підключення сигналу та натисніть «Підключити». Ви прагнете, щоб сигнал хіт надсилався з Player і оброблявся в Main сценарії. Додайте наступний код до нової функції, а також функцію new_game, яка налаштує все для нової гри:

func game_over():
    $ScoreTimer.stop()
    $MobTimer.stop()

func new_game():
    score = 0
    $Player.start($StartPosition.position)
    $StartTimer.start()

Тепер ми підключимо сигнал timeout() кожного вузла Таймера (StartTimer, ScoreTimer та MobTimer) до основного скрипта. Для кожного з трьох таймерів виберіть таймер на панелі Сцена, відкрийте вкладку Сигнали на панелі Вузлів, потім двічі клацніть сигнал timeout() у списку. Це відкриє діалогове вікно підключення нового сигналу. Налаштування за замовчуванням у цьому діалоговому вікні мають бути влаштовними, тому виберіть Підключити, щоб створити нове підключення сигналу.

Після того, як усі три таймери налаштовано, ви зможете побачити, що кожен таймер має підключення Signal для відповідного сигналу timeout(), що відображається зеленим кольором, у відповідних вкладках Signals:

  • (Для MobTimer): _on_mob_timer_timeout()

  • (Для ScoreTimer): _on_score_timer_timeout()

  • (Для StartTimer): _on_start_timer_timeout()

Тепер ми визначимо, як працює кожен із цих таймерів, додавши наведений нижче код. Зверніть увагу, що StartTimer запустить два інших таймери, а ScoreTimer збільшить рахунок на 1.

func _on_score_timer_timeout():
    score += 1

func _on_start_timer_timeout():
    $MobTimer.start()
    $ScoreTimer.start()

У функції _on_mob_timer_timeout() ми створимо екземпляр моба, підберемо випадкове початкове місце уздовж Path2D та приведемо моба у рух. Вузол PathFollow2D буде автоматично обертатися по мірі просування по шляху, так що ми будемо використовувати його, щоб вибрати напрямок моба, а також його позицію. Під час появи моба, ми вибираємо випадкове значення між 150.0 і 250.0 визначаючи швидкість руху (було б нудно, якби всі вони рухалися з однаковою швидкістю).

Зауважте, що новий екземпляр потрібно додати до сцени за допомогою add_child().

func _on_mob_timer_timeout():
    # Create a new instance of the Mob scene.
    var mob = mob_scene.instantiate()

    # Choose a random location on Path2D.
    var mob_spawn_location = $MobPath/MobSpawnLocation
    mob_spawn_location.progress_ratio = randf()

    # Set the mob's position to the random location.
    mob.position = mob_spawn_location.position

    # Set the mob's direction perpendicular to the path direction.
    var direction = mob_spawn_location.rotation + PI / 2

    # Add some randomness to the direction.
    direction += randf_range(-PI / 4, PI / 4)
    mob.rotation = direction

    # Choose the velocity for the mob.
    var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
    mob.linear_velocity = velocity.rotated(direction)

    # Spawn the mob by adding it to the Main scene.
    add_child(mob)

Важливо

Чому PI? У функціях, що вимагають кутів, Godot використовує радіани , а не градуси. Пі являє собою половину повороту в радіанах, близько 3.1415 (є також TAU, що дорівнює 2 * PI). Якщо вам зручніше працювати з градусами, вам потрібно буде скористатися функціями deg_to_rad() та rad_to_deg() для перетворення між ними.

Тестування сцени

Давайте протестуємо сцену, щоб переконати, що все працює. Додайте new_game до _ready():

func _ready():
    new_game()

Також визначимо Main, як нашу "Головну Сцену" - вона буде запускатися автоматично при кожному запуску гри. Натисніть кнопку "Відтворити" і виберіть main.tscn при появі запиту.

Порада

Якщо ви вже встановили іншу сцену як "Головну сцену", ви можете клацнути правою кнопкою мишки по main.tscn на панелі Файлова система і вибрати "Встановити головною сценою".

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

Переконавшись, що все працює вилучає виклик new_game() з _ready() і замініть його на pass.

Чого не вистачає нашій грі? Деякого інтерфейсу. На наступному уроці ми додамо титульний екран і відображення рахунку гравця.