Генерация уникальной последовательности платформ в виде решётки, в которой лишь пара платформ в каждом ряду пригодны для запрыгивания, является типичной для игровых режимов в стиле «платформера». Такое препятствие заставляет игроков притормозить и продумать последовательность прыжков.
В этом уроке рассмотрен порядок генерации решётки платформ, в которой в каждом ряду выбираются случайные платформы, имеющие коллизию и отличающий их светлый цвет, тогда как другие платформы не имеют коллизии и цветового выделения.
Создание заготовки платформы
Выполните следующие действия, чтобы создать готовый элемент платформы с помощью Verse:
Разместите новый модуль и сделайте из него заготовку select_one_platform_prefab. Инструкции см. в разделе Заготовки и их экземпляры.
В редакторе готовых элементов добавьте в модуль следующие компоненты:
transform_component: компонент преобразования, определяющий расположение платформы.
mesh_component: компонент сетки для прикрепления к платформе статичной сетки. В этом примере используется сетка SM_block_02 из пакета Stylized Egyptian World, который есть в магазине Fab.
collision_component: компонент коллизии для включения и отключения коллизии платформы.
parent_constraint_component: родительский компонент ограничения для простой настройки преобразования относительно родительского модуля при создании этой заготовки в мире с помощью Verse.
Добавьте дочерний модуль и назовите его Light.
Добавьте следующие компоненты в дочерний модуль Light:
transform_component: компонент преобразования, который размещает модуль над платформой.
point_light_component: компонент точечного источника света, который изменяет цвет при столкновении платформы.
parent_constraint_component: компонент ограничения по родительскому элементу, который ограничивает преобразование этого модуля относительно родительского модуля.
Сохраните заготовку.
Теперь ваша заготовка появится в файле Assets.digest.Verse как класс с тем же названием, что и у вашей заготовки же именем, что и у вашей заготовки, — choose_one_platform_prefab.
Создание решётки для платформ
Выполните следующие действия, чтобы создать решётку из готового элемента платформы:
Создайте компонент Verse с названием choose_one_component. Чтобы узнать, как создать компонент Verse, см. статью Создание собственного компонента с помощью Verse.
Добавьте следующие редактируемые свойства:
Поле целочисленного двухмерного вектора
vector2iс названиемGridSize, определяющее количество платформ в решётке. X — это количество рядов, а Y — количество столбцов в решётке.Поле двухмерного вектора с плавающей запятой
vector2с названиемPlatformSpacingдля определения интервала между платформами в рядах и столбцах.~~~(verse) GridSizeTip<localizes>:message = "Размер решётки, при котором она имеет ширину X единиц и длину Y единиц." PlatformSpacingTip<localizes>:message = "Расстояние между платформами в решётке."
choose_one_component<public> := class(component):
# Размер решётки в единицах, где X — её ширина, а Y — глубина. @editable_vector_number(int): ToolTip := GridSizeTip MinComponentValue := option{0} GridSize:vector2i = vector2i{X := 3, Y := 10}
# Расстояние между платформами в решётке. @editable_vector_number(float): ToolTip := PlatformSpacingTip MinComponentValue := option{0.0} PlatformSpacing:vector2 = vector2{X := 256.0, Y := 256.0} ~~~
В функции
OnSimulateсоздадим вложенный цикл, число итераций в котором определяется векторомGridSize, чтобы получить нужное число платформ. В цикле будем создавать экземпляр класса готового элемента и добавлять его к модулю, к которому прикреплён этот компонент Verse, чтобы создать готовый элемент в мире.~~~(verse) GridSizeTip<localizes>:message = "Размер решётки, при котором она имеет ширину X единиц и длину Y единиц." PlatformSpacingTip<localizes>:message = "Расстояние между платформами в решётке."
choose_one_component<public> := class(component):
# Размер решётки в единицах, где X — её ширина, а Y — глубина. @editable_vector_number(int): ToolTip := GridSizeTip MinComponentValue := option{0} GridSize:vector2i = vector2i{X := 3, Y := 10}
# Расстояние между платформами в решётке. @editable_vector_number(float): ToolTip := PlatformSpacingTip MinComponentValue := option{0.0} PlatformSpacing:vector2 = vector2{X := 256.0, Y := 256.0}
OnSimulate<override>()<suspends>:void= # Создаём платформы в мире, чтобы создать решётку. for (Column := 0..GridSize.Y - 1): for (Row := 0..GridSize.X - 1): # Создание экземпляра готового элемента и его добавление к существующему модулю приведёт к появлению этого элемента в мире. ChooseOnePlatform := choose_one_platform_prefab{} Entity.AddEntities(array{ChooseOnePlatform}) ~~~
Если запустить код прямо сейчас, все платформы появятся в одном месте. Поскольку заготовка содержит компонент преобразования и компонент ограничения по родительскому элементу, можно задать свойство InitialRelativeTransform для компонента преобразования, чтобы создать заготовку со смещением относительно местоположения модуля, к которому вы добавляете заготовку. Без родительского компонента ограничения для модуля, который требуется создать в мире, вам пришлось бы указывать местоположение в пространстве мира (а не относительно корневого модуля).
VerseGridSizeTip<localizes>:message = "Size of the grid, where the grid is X units wide by Y units deep." PlatformSpacingTip<localizes>:message = "The distance between each platform on the grid." choose_one_component<public> := class(component): # Size of the grid, where the grid is X units wide by Y units deep. @editable_vector_number(int): ToolTip := GridSizeTip MinComponentValue := option{0} GridSize:vector2i = vector2i{X := 3, Y := 10}Сохраните и скомпилируйте код.
Если присоединить этот компонент Verse к модулю и запустить сеанс, решётка платформ появится в месте расположения этого модуля.
Случайный выбор платформ, пригодных для запрыгивания
Теперь, когда у вас есть решётка из платформ, созданных в мире, к ним можно добавить новые функции. Ниже описан порядок случайного выбора платформ с коллизией, чтобы сгенерировать уникальную меняющуюся последовательность платформ, по которым должен прыгать игрок.
Следуйте этим указаниям, чтобы пригодные для запрыгивания платформы в решётке выбирались случайным образом:
Добавьте следующие редактируемые свойства в компонент Verse:
целочисленную переменную
MinCorrectPlatformsPerRowдля задания минимального количества платформ с коллизией;целочисленную переменную
MaxCorrectPlatformsPerRowдля определения максимального количества Платформ, у которых есть коллизия;переменную цвета
ChosenColorдля цвета платформы, если коллизия включена;переменную цвета
NotChosenColorдля цвета платформы, если коллизия отключена.Verseusing { /UnrealEngine.com/Temporary/SceneGraph } using { /UnrealEngine.com/Temporary/SpatialMath } using { /Verse.org } using { /Verse.org/Colors } using { /Verse.org/Native } using { /Verse.org/Random } using { /Verse.org/Simulation } GridSizeTip<localizes>:message = "Size of the grid, where the grid is X units wide by Y units deep." PlatformSpacingTip<localizes>:message = "The distance between each platform on the grid."
Результатом выполнения выражения
forявляется массив, элементы которого определяются на каждой итерации. Сохраним все созданные в ряду платформы в массиве и передадим этот массив в функциюRandomizeCollidablePlatformsPerRow(), которая выбирает платформы случайным образом.VerseOnSimulate<override>()<suspends>:void= # For each row, spawn multiple platforms and pick a number of them to have collision while the others don't. # The platforms with collision will have the Chosen color for their light component. # The platforms without collision will have the NotChosen color for their light component. for (Row := 0..GridSize.Y - 1): EntitiesInRow := for (Column := 0..GridSize.X - 1): # The prefab has a parent constraint component so set the InitialRelative Transform # on the transform component to offset each platform relative to this entity. # This means the platform prefabs will spawn same distance from each other # but moving the root entity will change where the platforms originate.Создайте функцию
RandomizeCollidablePlatformsPerRow, которая должна случайным образом выбирать модули с коллизией, и пусть она отключит коллизию для всех модулей. Так как компонент точечного источника света находится в дочернем модуле готового элемента, можно использоватьFindComponentsдля поиска дочерних элементов модуля, чтобы изменить цвет точечного источника.Verse# Randomly choose platforms to have collision in the row. RandomizeCollidablePlatformsPerRow(Entities:[]entity):void= # Disable all the entities before choosing which ones to enable. # It disables an entity by disabling the collision on the entity, # and finding a point light in its child entities to change its color. for: EntityPlatform : Entities Collision := EntityPlatform.GetComponents(collision_component)[0] Light := EntityPlatform.FindComponents(point_light_component)[0] do:Создайте метод расширения для массивов
ChooseOne, который будет выбирать случайный элемент из массива. Результатом выполнения метода должен быть кортеж, содержащий как выбранный элемент, так и массив со всеми остальными элементами, которые не выбраны.Verse# An extension method for an array to get a randomly selected element from the array. (Input:[]t where t:subtype(comparable)).ChooseOne()<decides><transacts>:tuple(t, []t)= ChosenElement := Input[GetRandomInt(0, Input.Length - 1)] NotChosenElements := Input.RemoveFirstElement[ChosenElement] (ChosenElement, NotChosenElements)Вызовите
ChooseOneизRandomizeCollidablePlatformsPerRow, чтобы выбрать модуль с коллизией и изменить его цвет.Verse# Randomly choose platforms to have collision in the row. RandomizeCollidablePlatformsPerRow(Entities:[]entity):void= # Disable all the entities before choosing which ones to enable. # It disables an entity by disabling the collision on the entity, # and finding a point light in its child entities to change its color. for: EntityPlatform : Entities Collision := EntityPlatform.GetComponents(collision_component)[0] Light := EntityPlatform.FindComponents(point_light_component)[0] do:Обновите
RandomizeCollidablePlatformsPerRowтаким образом, чтобы выбирать несколько модулей, которые должны иметь коллизию, на основе редактируемых свойств. Сначала получите случайное значение в пределах от минимума до максимума подходящих платформ в каждом ряду и выберите модуль соответствующее число раз, а затем удалите выбранный модуль из списка модулей, доступных для выбора на следующем шаге.Verse# Randomly choose platforms to have collision in the row. RandomizeCollidablePlatformsPerRow(Entities:[]entity):void= # Disable all the entities before choosing which ones to enable. # It disables an entity by disabling the collision on the entity, # and finding a point light in its child entities to change its color. for: EntityPlatform : Entities Collision := EntityPlatform.GetComponents(collision_component)[0] Light := EntityPlatform.FindComponents(point_light_component)[0] do:Сохраните и скомпилируйте код.
Если сейчас запустить сеанс, в мире будет создана решётка платформ с уникальной последовательностью платформ, имеющих коллизию и выбранный цвет.
Полный сценарий
using { /UnrealEngine.com/Temporary/SceneGraph }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org }
using { /Verse.org/Colors }
using { /Verse.org/Native }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
GridSizeTip<localizes>:message = "Size of the grid, where the grid is X units wide by Y units deep."
PlatformSpacingTip<localizes>:message = "The distance between each platform on the grid."