Головна сцена гри
Тепер настав час об'єднати все, що ми зробили, разом, в ігрову сцену.
Створіть нову сцену та додайте Node <class_Node>`*(Вузол)* з ім'ям ``Main`. (Ми використовуємо Node, а не Node2D, тому що саме цей вузол буде контейнером для обробки логіки гри. Він не вимагає 2D-функціональності.)
Клацніть кнопку Створити екземпляр дочірньої сцени (іконка ланцюжка) і виберіть збережений player.tscn.
Тепер додайте наступні вузли як дочірні вузли Main і назвіть їх, як показано:
Timer (названий
MobTimer) - щоб контролювати, як часто виникають мобиTimer (названий
ScoreTimer) - збільшуватиме рахунок щосекундиTimer (названий
StartTimer) - щоб дати затримку перед запускомMarker2D (названий
StartPosition) - для визначення стартової позиції гравця
Встановіть властивість Час очікування кожного з вузлів Таймер наступним чином (значення в секундах):
MobTimer:0.5ScoreTimer:1StartTimer: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:
Виберіть середню ("Додати точку") та намалюйте шлях, клацнувши, щоб додати точки у вказаних кутах. Щоб точки прикріпилися до сітки (ґратки), переконайтеся, що опції "Використати до ґратки" та "Використати прив'язку", обидві включені. Ці опції можна знайти зліва від кнопки «Блокування», виглядає як магніт з кількома лініями, що перетинаються.
Важливо
Малюйте доріжку за годинниковою стрілкою , інакше ваші моби будуть виникати спрямовані назовні, а не всередину!
Після розміщення четвертої точки на зображенні натисніть кнопку "Закрити криву", і ваша крива буде завершена.
Тепер, коли шлях визначений, додайте вузол PathFollow2D (слідувати за шляхом 2D) нащадком MobPath та назвіть його MobSpawnLocation. Цей вузол автоматично обертатиметься та рухатиметься по шляху, тому ми можемо використовувати його для вибору випадкової позиції та напрямку вздовж шляху.
Ваше сцена має виглядати так:
Головний скрипт
Додайте скрипт до вузла Main. У верхній частині скрипту ми використовуємо @export var mob_scene: PackedScene, щоб ми могли вибрати сцену Mob, екземпляр якої ми хочемо створити.
extends Node
@export var mob_scene: PackedScene
var score
using Godot;
public partial class Main : Node
{
// Don't forget to rebuild the project so the editor knows about the new export variable.
[Export]
public PackedScene MobScene { get; set; }
private int _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()
public void GameOver()
{
GetNode<Timer>("MobTimer").Stop();
GetNode<Timer>("ScoreTimer").Stop();
}
public void NewGame()
{
_score = 0;
var player = GetNode<Player>("Player");
var startPosition = GetNode<Marker2D>("StartPosition");
player.Start(startPosition.Position);
GetNode<Timer>("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()
// We also specified this function name in PascalCase in the editor's connection window.
private void OnScoreTimerTimeout()
{
_score++;
}
// We also specified this function name in PascalCase in the editor's connection window.
private void OnStartTimerTimeout()
{
GetNode<Timer>("MobTimer").Start();
GetNode<Timer>("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)
// We also specified this function name in PascalCase in the editor's connection window.
private void OnMobTimerTimeout()
{
// Create a new instance of the Mob scene.
Mob mob = MobScene.Instantiate<Mob>();
// Choose a random location on Path2D.
var mobSpawnLocation = GetNode<PathFollow2D>("MobPath/MobSpawnLocation");
mobSpawnLocation.ProgressRatio = GD.Randf();
// Set the mob's direction perpendicular to the path direction.
float direction = mobSpawnLocation.Rotation + Mathf.Pi / 2;
// Set the mob's position to a random location.
mob.Position = mobSpawnLocation.Position;
// Add some randomness to the direction.
direction += (float)GD.RandRange(-Mathf.Pi / 4, Mathf.Pi / 4);
mob.Rotation = direction;
// Choose the velocity.
var velocity = new Vector2((float)GD.RandRange(150.0, 250.0), 0);
mob.LinearVelocity = velocity.Rotated(direction);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
Важливо
Чому PI? У функціях, що вимагають кутів, Godot використовує радіани , а не градуси. Пі являє собою половину повороту в радіанах, близько 3.1415 (є також TAU, що дорівнює 2 * PI). Якщо вам зручніше працювати з градусами, вам потрібно буде скористатися функціями deg_to_rad() та rad_to_deg() для перетворення між ними.
Тестування сцени
Давайте протестуємо сцену, щоб переконати, що все працює. Додайте new_game до _ready():
func _ready():
new_game()
public override void _Ready()
{
NewGame();
}
Також визначимо Main, як нашу "Головну Сцену" - вона буде запускатися автоматично при кожному запуску гри. Натисніть кнопку "Відтворити" і виберіть main.tscn при появі запиту.
Порада
Якщо ви вже встановили іншу сцену як "Головну сцену", ви можете клацнути правою кнопкою мишки по main.tscn на панелі Файлова система і вибрати "Встановити головною сценою".
Ви мали би успішно переміщати повсюди гравця, спостерігати, як народжуються моби, і бачити, як зникає гравець при зіткненні з мобом.
Переконавшись, що все працює видаліть виклик new_game() з _ready() і замініть його на pass.
Чого не вистачає нашій грі? Деякого інтерфейсу. На наступному уроці ми додамо титульний екран і відображення рахунку гравця.