Проектування сцени монстра

У цій частині ви збираєтеся кодувати монстрів, яких будемо називати мобами. На наступному уроці ми будемо розміщувати їх випадковим чином навколо ігрової області.

Давайте спроектуємо самих монстрів в новій сцені. Структура вузлів буде схожа на сцену гравця Player.

Знову створіть сцену з одним вузлом KinematicBody в якості кореня. Назвіть його Mob. Додайте вузол Spatial в якості нащадка і назвіть його Pivot. Виділіть і перетягніть файл mob.glb з панелі Файлова система на Pivot, щоб додати 3D модель монстра до сцени. Ви можете перейменувати щойно створений вузол mob на Character.

image0

Нам потрібна форма зіткнення, для роботи тіла. Клацніть правою кнопкою миші на вузлі Mob, корені сцени, і натисніть Додати дочірній вузол.

image1

Додайте CollisionShape.

image2

У Інспекторі призначте властивості Shape стан BoxShape.

image3

Ми повинні змінити його розмір, щоб краще відповідати розміру 3D-моделі. Ви можете зробити це інтерактивно, натиснувши та перетягнувши помаранчеві точки.

Коробка повинна торкатися підлоги і бути трохи тонше моделі. Фізичні рушії працюють таким чином, що якщо сфера гравця торкнеться навіть кута коробки, відбудеться зіткнення. Якщо коробка трохи завелика в порівнянні з 3D-моделлю, ви можете померти на відстані від монстра, і гра буде несправедливою по відношенню до гравців.

image4

Зверніть увагу, що моя коробка вище, ніж монстр. Це нормально в цій грі, тому що ми дивимося на сцену зверху і використовуємо фіксовану перспективу. Форми зіткнення не повинні точно відповідати моделі. Це та форма та розмір, які гра відчуває, коли ви тестуєте її.

Видалення монстрів поза екраном

Ми збираємося створювати монстрів через регулярні проміжки часу на ігровому рівні. Якщо ми не будемо обережні, їх кількість може збільшитися до нескінченності, а ми цього не хочемо. Кожен екземпляр моба займає як пам'ять, так і процес обробки, але нам не потрібно це, для монстрів які знаходиться за межами екрана.

Як тільки монстр покидає екран, він нам більше не потрібен, тому ми можемо видалити його. Godot має вузол, який виявляє, коли об'єкти залишають екран, VisibilityNotifier, і ми збираємося використовувати його, щоб знищити наших монстрів.

Примітка

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

При роботі з GDScript вам не потрібно турбуватися про це. Основна причина використання об'єднань полягає в тому, щоб уникнути замерзання в мовах, що збирають сміття, такими як C#, або Lua. GDScript використовує інший метод для управління пам'яттю, підрахунком посилань, тому не має такого застереження. Ви можете дізнатися більше про це тут Управління пам'яттю.

Виберіть вузол Mob і додайте VisibilityNotifier в якості нащадка. З'явиться ще одна коробка, на цей раз, рожева. Коли ця коробка повністю покине екран, вузол буде випромінювати сигнал.

image5

Змініть коробку за допомогою помаранчевих точок, щоб вона охопила всю 3D-модель.

Зображення

Кодування руху монстра

Давайте реалізуємо рух монстра. Ми зробимо це в два етапи. По-перше, ми напишемо скрипт для Mob, який визначає функцію ініціалізації монстра. Потім ми закодуємо механізм випадкової появи на головній сцені Main і викличемо функцію звідти.

Доєднайте скрипт до вузла Mob.

image7

Ось початковий код руху. Визначаємо дві властивості, min_speed і max_speed, щоб визначити діапазон випадкової швидкості. Потім ми визначаємо та ініціалізуємо velocity.

extends KinematicBody

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
    move_and_slide(velocity)

Подібно до гравця, ми переміщуємо моб кожен кадр, викликаючи метод move_and_slide() з KinematicBody. На цей раз ми не оновлюємо velocity кожен кадр: ми хочемо, щоб монстр рухався з постійною швидкістю і залишав екран, навіть якщо зіткнувся з перешкодою.

Ви можете побачити попередження в GDScript про те, що повернуте значення з move_and_slide() не використовується. Це очікувано. Ви можете просто проігнорувати попередження або, якщо хочете повністю приховати його, додати коментар # warning-ignore:return_value_discarded трохи вище рядка move_and_slide(velocity). Щоб дізнатися більше про систему попереджень GDScript, див. Система попередження GDScript.

Нам потрібно визначити іншу функцію для розрахунку початкової швидкості. Ця функція поверне монстра в напрямку гравця і задасть йому випадкові кут руху та швидкість.

Функція прийме позицію появи монстра start_position і позицію гравця player_position в якості аргументів.

Спочатку ми розміщуємо монстра на start_position і повертаємо його до гравця за допомогою методу look_at_from_position() і задаємо випадковий кут, обертаючи по осі Y. Нижче rand_range() виводить випадкове значення між радіанами -PI / 4 і радіанами PI / 4.

# We will call this function from the Main scene.
func initialize(start_position, player_position):
    # We position the mob and turn it so that it looks at the player.
    look_at_from_position(start_position, player_position, Vector3.UP)
    # And rotate it randomly so it doesn't move exactly toward the player.
    rotate_y(rand_range(-PI / 4, PI / 4))

Потім вираховуємо випадкову швидкість, використовуючи rand_range() ще раз.

Ми починаємо зі створення 3D-вектора, що вказує вперед, множимо його на наш випадкову швидкість random_speed, і, нарешті, обертаємо його за допомогою методу rotated() класу Vector3.

func initialize(start_position, player_position):
    # ...

    # We calculate a random speed.
    var random_speed = rand_range(min_speed, max_speed)
    # We calculate a forward velocity that represents the speed.
    velocity = Vector3.FORWARD * random_speed
    # We then rotate the vector based on the mob's Y rotation to move in the direction it's looking.
    velocity = velocity.rotated(Vector3.UP, rotation.y)

Залишання екрану

Ми все ще повинні знищувати монстрів, коли вони залишають екран. Для цього ми підключимо сигнал screen_exited нашого вузла VisibilityNotifier до Mob.

Поверніться до 3D вікна перегляду, натиснувши на мітку 3D у верхній частині редактора. Ви також можете натиснути Ctrl + F2 (:kbd:`Alt + 2`на macOS).

image8

Виберіть вузол VisibilityNotifier і в правій частині інтерфейсу перейдіть до панелі Вузол. Двічі клацніть сигнал screen_exited().

image9

Підключіть сигнал до Mob.

image10

Це поверне вас до редактора скриптів і створить для вас нову функцію, _on_VisibilityNotifier_screen_exited(). З неї викличте метод queue_free(). Це знищить екземпляр монстра, коли коробка VisibilityNotifier покине екран.

func _on_VisibilityNotifier_screen_exited():
    queue_free()

Наш монстр готовий появитися в грі! У наступній частині ви будете породжувати монстрів на ігровому рівні.

Ось повний скрипт Mob.gd для довідки.

extends KinematicBody

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
    move_and_slide(velocity)

func initialize(start_position, player_position):
    look_at_from_position(start_position, player_position, Vector3.UP)
    rotate_y(rand_range(-PI / 4, PI / 4))

    var random_speed = rand_range(min_speed, max_speed)
    velocity = Vector3.FORWARD * random_speed
    velocity = velocity.rotated(Vector3.UP, rotation.y)


func _on_VisibilityNotifier_screen_exited():
    queue_free()