Спавн монстров

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

image0

Дважды щёлкните на Main.tscn в панели FileSystem, чтобы открыть сцену Main.

Прежде чем рисовать путь, мы изменим разрешение игры. Наша игра имеет размер окна по умолчанию 1024x600. Мы установим его на 720x540, маленькую красивую рамку.

Перейдите в Проект -> Настройки проекта.

image1

В левом меню перейдите вниз к Display -> Window. Справа установите значение Width на 720 и значение Height на 540.

image2

Создание пути спавна

Как и в учебнике по 2D-играм, вы собираетесь спроектировать путь и использовать узел PathFollow для выборки случайных мест на нём.

Однако в 3D рисовать путь немного сложнее. Мы хотим, чтобы он был вокруг игрового вида, чтобы монстры появлялись прямо за экраном. Но если мы нарисуем путь, мы не увидим его из предварительного просмотра камеры.

Чтобы определить границы вида, мы можем использовать некоторые сетки. Ваш экран всё ещё должен быть разделён на две части, с предварительным просмотром камеры в нижней части. Если это не так, нажмите Ctrl + 2 (Cmd + 2 на macOS), чтобы разделить вид на две части. Выберите узел Camera и установите флажок Preview в нижнем окне просмотра.

image3

Добавление заполнителей цилиндров

Давайте добавим сетки-заполнители. Добавьте новый узел Spatial в качестве дочернего узла Main и назовите его Cylinders. Мы будем использовать его для группировки цилиндров. В качестве дочернего узла добавьте узел MeshInstance.

image4

В инспекторе назначьте CylinderMesh свойству Mesh.

image5

Установите верхний экран на ортогональный вид сверху с помощью меню в левом верхнем углу экрана. Также можно нажать клавишу 7 на клавиатуре.

image6

Для меня сетка немного отвлекает. Вы можете переключить её, перейдя в меню View на панели инструментов и выбрав View Grid.

image7

Теперь нужно переместить цилиндр вдоль плоскости земли, глядя на предварительный просмотр камеры в нижнем окне просмотра. Я рекомендую использовать для этого привязку к сетке. Её можно переключить, нажав на значок магнита на панели инструментов или нажав Y.

image8

Поместите цилиндр так, чтобы он находился прямо за пределами обзора камеры в левом верхнем углу.

image9

Мы собираемся создать копии сетки и разместить их вокруг игровой области. Нажмите Ctrl + D (Cmd + D на macOS), чтобы продублировать узел. Вы также можете щёлкнуть узел правой кнопкой мыши в панели Scene и выбрать Duplicate. Переместите копию вниз вдоль синей оси Z, пока она не окажется прямо за пределами предварительного просмотра камеры.

Выберите оба цилиндра, нажав клавишу Shift и щёлкнув по невыбранному цилиндру продублируйте их.

image10

Переместите их вправо, перетащив красную ось X.

image11

Их немного трудно разглядеть в белом цвете, не так ли? Давайте выделим их, придав им новый материал.

В 3D, материалы определяют визуальные свойства поверхности, такие как цвет, отражение света и многое другое. Мы можем использовать их для изменения цвета сетки.

Мы можем обновить все четыре цилиндра одновременно. Выберите все экземпляры сетки в панели Scene. Для этого щёлкните на первом из них и щёлкните с зажатым Shift на последнем.

image12

В инспекторе, раскройте раздел Material и назначьте SpatialMaterial в слот 0.

image13

Щёлкните значок сферы, чтобы открыть ресурс материала. Вы получите предварительный просмотр материала и длинный список разделов, заполненных свойствами. С их помощью можно создавать всевозможные поверхности, от металла до камня или воды.

Разверните раздел Albedo и установите цвет, контрастирующий с фоном, например, ярко-оранжевый.

image14

Теперь мы можем использовать цилиндры в качестве направляющих. Сложите их в панели Scene, нажав на серую стрелку рядом с ними. Продвигаясь вперёд, вы также можете переключить их видимость, нажав на значок глаза рядом с Цилиндрами.

image15

Добавьте узел Path в качестве дочернего узла Main. На панели инструментов появятся четыре значка. Щёлкните инструмент Add Point (добавить точку) - значок с зелёным знаком "+".

image16

Примечание

Наведя курсор на любой значок, можно увидеть всплывающую подсказку с описанием инструмента.

Щёлкните в центре каждого цилиндра, чтобы создать точку. Затем нажмите на значок Close Curve (Закрыть кривую) на панели инструментов, чтобы закрыть контур. Если какая-либо точка немного смещена, можно щёлкнуть и перетащить её, чтобы изменить положение.

image17

Ваш путь должен выглядеть следующим образом.

image18

Для выборки случайных позиций на нём нам нужен узел PathFollow. Добавьте узел PathFollow в качестве дочернего узла Path. Переименуйте эти два узла в SpawnPath и SpawnLocation соответственно. Это более точно описывает то, для чего мы будем их использовать.

|изображение19|

После этого мы готовы к написанию кода механизма порождения.

Случайный спавн монстров

Щелкните правой кнопкой мыши на узле Main и прикрепите к нему новый скрипт.

Сначала мы экспортируем переменную в инспекторе, чтобы мы могли присвоить ей Mob.tscn или любого другого монстра.

Затем, поскольку мы собираемся порождать монстров процедурно, мы хотим случайно вычислять числа каждый раз, когда играем в игру. Если этого не сделать, монстры всегда будут появляться в одной и той же последовательности.

extends Node

export (PackedScene) var mob_scene


func _ready():
    randomize()

Мы хотим порождать мобов через регулярные промежутки времени. Для этого нам нужно вернуться на сцену и добавить таймер. Но перед этим нам нужно назначить файл Mob.tscn свойству mob_scene.

Вернитесь на 3D-экран и выберите узел Main. Перетащите Mob.tscn из панели FileSystem в слот Mob Scene в инспекторе.

|изображение20|

Добавьте новый узел Timer как дочерний узел Main. Назовите его MobTimer.

|изображение21|

В инспекторе установите Wait Time на 0.5 секунд и включите Autostart, чтобы он автоматически запускался, когда мы запустим игру.

|изображение22|

Таймеры издают сигнал timeout каждый раз, когда они достигают конца своего времени ожидания (Wait Time). По умолчанию они перезапускаются автоматически, испуская сигнал в цикле. Мы можем подключиться к этому сигналу из узла Main, чтобы порождать монстров каждые 0.5 секунды.

Когда MobTimer всё ещё выбран, перейдите в панель Node справа и дважды щёлкните по сигналу timeout.

|изображение23|

Подключите его к узлу Main.

|изображение24|

Это вернёт вас к скрипту с новой пустой функцией _on_MobTimer_timeout().

Давайте напишем логику порождения мобов. Мы собираемся:

  1. Добавить подвижный объект на сцену.

  2. Выборка случайной позиции на пути порождения.

  3. Получить позицию игрока.

  4. Вызовите метод initialize() моба, передав ему случайную позицию и позицию игрока.

  5. Добавьте подвижный объект в качестве дочернего элемента узла 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)

Выше, randf() выдаёт случайное значение между 0 и 1, что и ожидает узел PathFollow узла unit_offset.

Вот, для справки, полный скрипт 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)

Вы можете протестировать сцену, нажав F6. Вы должны увидеть, что монстры появляются и движутся по прямой линии.

|изображение25|

Пока что они сталкиваются и скользят друг по другу, когда их пути пересекаются. Мы рассмотрим это в следующей части.