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

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

Створіть нову сцену та додайте Node <class_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).

Поява мобів

The Main node will be spawning new mobs, and we want them to appear at a random location on the edge of the screen. Click the Main node in the Scene dock, then add a child Path2D node named MobPath. When you select Path2D, you will see some new buttons at the top of the editor:

../../_images/path2d_buttons.webp

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

../../_images/grid_snap_button.webp

Важливо

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

../../_images/draw_path2d.gif

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

Тепер, коли шлях визначений, додайте вузол 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.

Далі виберіть вузол Player на вузлі Main на панелі Сцена і відкрийте панель Вузла збоку. Переконайтесь, що на панелі Вузла вибрано Сигнали.

Ви повинні побачити список сигналів для вузла Гравець. Знайдіть і двічі клацніть сигнал 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()

Now we'll connect the timeout() signal of each Timer node (StartTimer, ScoreTimer, and MobTimer) to the main script. For each of the three timers, select the timer in the Scene dock, open the Signals tab of the Node dock, then double-click the timeout() signal in the list. This will open a new signal connection dialog. The default settings in this dialog should be fine, so select Connect to create a new signal connection.

Once all three timers have this set up, you should be able to see each timer have a Signal connection for their respective timeout() signal, showing in green, within their respective Signals tabs:

  • (For MobTimer): _on_mob_timer_timeout()

  • (For ScoreTimer): _on_score_timer_timeout()

  • (For StartTimer): _on_start_timer_timeout()

Now we define how each of these timers operate by adding the code below. Notice that StartTimer will start the other two timers, and that ScoreTimer will increment the score by 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.

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