Поява монстрів¶
У цій частині ми збираємося випадковим чином створювати монстрів уздовж шляху. Зрештою, у вас будуть монстри, що бродять по ігровій дошці.
Двічі клацніть по Main.tscn
в панелі Файлова система, щоб відкрити головну сцену Main.
Перш ніж малювати шлях, нам треба змінити роздільну здатність гри. Наша гра має розмір вікна за замовчуванням 1024x600
. Ми збираємося встановити його на 720x540
, хороша маленька коробка.
Перейдіть до Проект -> Параметри проекту.
В лівому меню перейдіть до Display -> Window. Праворуч встановіть для Width 720
і для Height 540
.
Створення шляху на якому з'являтимуться монстри¶
Як і в посібнику з 2D-гри, вам треба розробити шлях і використовувати вузол PathFollow для вибірки випадкових місць на ньому.
У 3D, однак, це трохи складніше. Ми хочемо, щоб він був навколо виду гри, щоб монстри з'являлися прямо за екраном. Але якщо ми намалюємо шлях, ми не побачимо його з попереднього перегляду камери.
Щоб знайти межі перегляду, ми можемо використовувати деякі меші (сітки) в якості орієнтирів. Ваше вікно перегляду все ще має бути розділеним на дві частини, із попереднім переглядом з камери внизу. Якщо це не так, натисніть Ctrl + 2 (Cmd + 2 на macOS), щоб розділити вікно перегляду на дві частини. Виберіть вузол камери та позначте галочку Попередній перегляд у нижньому вікні.
Додавання циліндрів-орієнтирів¶
Давайте додамо меші-орієнтири. Додайте новий вузол Spatial, в якості нащадка вузла Main та назвіть його Cylinders. Ми будемо використовувати його для групування циліндрів. Додайте йому в нащадки вузол MeshInstance.
В Інспекторі властивості Mesh призначте CylinderMesh.
Оберіть вигляд згори верхній ортогональний використовуючи меню вікна перегляду в лівому верхньому кутку, або скориставшись клавішею 7 цифрової клавіатури.
Зображення
Ґратка (сітка) трохи відволікає мене. Переключити її видимість можна, перейшовши до меню Перегляд на панелі інструментів і вибравши пункт Перегляд ґратки.
Тепер вам треба перемістити циліндр вздовж наземної площини, дивлячись на попередній перегляд камери в нижньому вікні перегляду. Я рекомендую робити це використовуючи прив'язку до ґратки. Ви можете перемикати прив'язку, клацаючи значок магніту на панелі інструментів, або натискаючи Y.
Розташуйте циліндр так, щоб він знаходився прямо за межами зору камери у верхньому лівому куті.
Ми збираємося створити копії меша і розмістити їх навколо ігрової зони. Натисніть Ctrl + D (Cmd + D на macOS), щоб дублювати вузол. Також можна клацнути правою кнопкою миші вузол на панелі Сцена та вибрати пункт Дублювати. Переміщуйте копію вниз по синій осі Z, доки вона не вийде за межі попереднього перегляду камери.
Виберіть обидва циліндри, натиснувши клавішу Shift і клацнувши по невибраному, і дублюйте їх.
Перемістіть їх праворуч по червоній осі X.
Білі циліндри трохи важко розгледіти, чи не так? Давайте виділимо їх, надавши їм новий матеріал.
У 3D матеріали визначають візуальні властивості поверхні, такі як її колір, те, як вона відбиває світло, тощо. Ми можемо використовувати їх для зміни кольору меша.
Ми можемо оновити всі чотири циліндри одночасно. Виберіть усі екземпляри меша на панелі Сцена. Для цього можна обрати перший і затиснувши Shift клацнути по останньому.
У Інспекторі розгорніть розділ Матеріал і призначте SpatialMaterial гнізду 0.
Клацніть піктограму сфери, щоб відкрити ресурс матеріалу. Ви отримуєте попередній перегляд матеріалу та довгий список розділів, заповнених властивостями. Ви можете використовувати їх для створення всіляких поверхонь, від металу до каміння, чи води.
Розгорніть розділ Albedo і встановіть колір на той, що контрастує з фоном, наприклад яскраво-помаранчевий.
Тепер ми можемо використовувати циліндри в якості орієнтирів. Згорніть їх на панелі Сцена натиснувши сіру стрілку поруч з ними. Надалі, ви також можете перемикати їх видимість, клацнувши значок ока поруч із Cylinders.
Додайте вузол Path в якості нащадка Main. На панелі інструментів з'являться чотири значка. Натисніть інструмент Додати точку, значок із зеленим знаком "+".
Примітка
Ви можете навести курсор на будь-яку піктограму, щоб побачити підказку з описом інструмента.
Клацніть по центру кожного циліндра, щоб створити точку. Потім клацніть піктограму Закрити криву на панелі інструментів, щоб закрити контур. Якщо якась точка трохи за межами, можете натиснути на неї і перетягнути, щоб змінити розташування.
Ваш шлях повинен виглядати так.
Щоб вибрати випадкові позиції на ньому, нам потрібен вузол PathFollow. Додайте PathFollow в якості нащадка Path. Перейменуйте обидва вузли на SpawnPath і SpawnLocation відповідно. Це краще описує те, для чого ми будемо їх використовувати.
З усім цим ми готові кодувати механізм появи монстрів.
Поява монстрів¶
Клацніть правою кнопкою миші на головному вузлі Main і прикріпіть до нього новий скрипт.
Спочатку ми експортуємо змінну до Інспектора, щоб ми могли призначити їй Mob.tscn
, або будь-якого іншого монстра.
Потім, коли ми будемо процедурно створювати монстрів, нам знадобиться випадковість, інакше монстри завжди будуть нереститися за тією ж послідовністю кожної гри.
extends Node
export (PackedScene) var mob_scene
func _ready():
randomize()
public class Main : Node
{
// Don't forget to rebuild the project so the editor knows about the new export variable.
#pragma warning disable 649
// We assign this in the editor, so we don't need the warning about not being assigned.
[Export]
public PackedScene MobScene;
#pragma warning restore 649
public override void _Ready()
{
GD.Randomize();
}
}
Ми хочемо щоби монстри появлялися через регулярні проміжки часу. Для цього нам потрібно повернутися на сцену і додати таймер. Але перед цим, однак, нам потрібно призначити файл Mob.tscn
властивості mob_scene
.
Поверніться на 3D-екран і виберіть вузол Main. Перетягніть Mob.tscn
курсором з панелі Файлова система до гнізда Mob Scene в Інспекторі.
Додайте новий вузол таймера Timer в якості нащадка Main. Назвіть його MobTimer.
У Інспекторі встановіть час очікування Wait Time на 0.5
секунди та увімкніть автозапуск Autostart, щоб таймер автоматично запускався разом із грою.
Таймери випромінюють сигнал timeout
кожного разу, коли вони досягають кінця свого часу очікування Wait Time. За замовчуванням вони перезавантажуються автоматично, випромінюючи сигнал в циклі. Ми можемо підключатися до цього сигналу від головного вузла Main, щоб налаштувати появу монстрів кожні 0.5
секунди.
Поки MobTimer ще обраний, перейдіть до панелі Вузол справа і двічі клацніть сигнал timeout
.
Підключіть його до головного вузла Main.
Це поверне вас до скрипта, з новою порожньою функцією _on_MobTimer_timeout()
.
Давайте кодувати логіку появи монстрів. Ми збираємося:
Вставити екземпляр (інстансувати) сцени монстра.
Отримати випадкове положення на шляху появи.
Отримати позицію гравця.
Викликати метод монстра
initialize()
, передаючи йому випадкову позицію і позицію гравця.Додати монстра в якості нащадка головного вузла Main.
func _on_MobTimer_timeout():
# Create a new instance of the Mob scene.
var mob = mob_scene.instance()
# Choose a random location on the SpawnPath.
# We store the reference to the SpawnLocation node.
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
# And give it a random offset.
mob_spawn_location.unit_offset = randf()
var player_position = $Player.transform.origin
mob.initialize(mob_spawn_location.translation, player_position)
add_child(mob)
// We also specified this function name in PascalCase in the editor's connection window
public void OnMobTimerTimeout()
{
// Create a new instance of the Mob scene.
Mob mob = (Mob)MobScene.Instance();
// Choose a random location on the SpawnPath.
// We store the reference to the SpawnLocation node.
var mobSpawnLocation = GetNode<PathFollow>("SpawnPath/SpawnLocation");
// And give it a random offset.
mobSpawnLocation.UnitOffset = GD.Randf();
Vector3 playerPosition = GetNode<Player>("Player").Transform.origin;
mob.Initialize(mobSpawnLocation.Translation, playerPosition);
AddChild(mob);
}
В коді вище, randf()
виробляє випадкове значення між 0
і 1
, що є тим, що очікує unit_offset
вузла PathFollow.
Ось повний скрипт Main.gd
наразі, для довідки.
extends Node
export (PackedScene) var mob_scene
func _ready():
randomize()
func _on_MobTimer_timeout():
var mob = mob_scene.instance()
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
mob_spawn_location.unit_offset = randf()
var player_position = $Player.transform.origin
mob.initialize(mob_spawn_location.translation, player_position)
add_child(mob)
public class Main : Node
{
#pragma warning disable 649
[Export]
public PackedScene MobScene;
#pragma warning restore 649
public override void _Ready()
{
GD.Randomize();
}
public void OnMobTimerTimeout()
{
Mob mob = (Mob)MobScene.Instance();
var mobSpawnLocation = GetNode<PathFollow>("SpawnPath/SpawnLocation");
mobSpawnLocation.UnitOffset = GD.Randf();
Vector3 playerPosition = GetNode<Player>("Player").Transform.origin;
mob.Initialize(mobSpawnLocation.Translation, playerPosition);
AddChild(mob);
}
}
Ви можете перевірити сцену, натиснувши F6. Ви повинні побачити як монстри появляються і рухатися по прямій лінії.
На даний момент вони стикаються і штурхаються між собою, коли їх шляхи перетинаються. Ми розглянемо це в наступній частині.