Маркеры целей используются во многих играх, чтобы направлять игрока к следующей цели или достопримечательности. В этом уроке вы узнаете, как создать повторно используемый маркер цели с помощью устройства Указатель на карте и Verse.
Используемые возможности языка Verse
структура: вы можете группировать переменные разного типа в структуру.
Метод расширения: особый тип функции, который действует как составляющая существующего класса или типа, не требуя при этом создания нового типа или подкласса. В этом уроке вы создадите метод расширения для структуры.
именованный аргумент: аргумент, который передаётся при вызове функции с указанным именем параметра.
Используемые API Verse
creative_prop API: API
creative_propпредоставляет методы для перемещения объектов окружения.Редактируемые свойства: несколько свойств используются как для ссылки на устройство, так и для обновления значений переменных в целях быстрого тестирования.
Указания
Выполните следующие шаги, чтобы узнать, как настроить одно устройство маркера цели, которое может перемещаться к нескольким целям или достопримечательностям. Для справки в конце данного руководства приведены полные сценарии.
Подготовка уровня
В этом примере используются следующие объекты окружения и устройства.
1 объект-здание: объект окружения для перемещения устройства «Указатель на карте».
1 x устройство «Индикатор на карте»: устройство, которое отображает пользовательские маркеры на мини-карте и обзорной карте.
1 устройство «Точка появления игрока»: разместите его около объекта окружения, чтобы игрок появился рядом с ним.
Использование API объекта окружения
Первый шаг в перемещении устройства с помощью Verse — это перемещение объекта окружения посредством API объекта окружения. Выполните следующие шаги, чтобы перемещать объект окружения по уровню.
Создайте новое устройство Verse и назовите его objective_coordinator_device.
После выражений
usingпо умолчанию в начале файла Verse добавьте выражениеusingдля модуля SpatialMath. Этот модуль содержит код, который вы будете использовать для перемещения объектов окружения.Verseusing { /UnrealEngine.com/Temporary/SpatialMath }Добавьте два редактируемых свойства:
Константу
creative_propс именемRootPropдля хранения ссылки на движущийся объект окружения.Константу
transformс именемНазначениедля хранения местоположения, куда будет перемещаться объект окружения.Verseobjective_coordinator_device<public> := class<concrete>(creative_device): @editable RootProp<public> : creative_prop = creative_prop{} @editable Destination<public> : transform = transform{}
Если вы запустите этот код и перетащите устройство objective_coordinator_device на уровень, оба свойства будут отображаться на панели Сведения.
Фактическое перемещение объекта окружения обеспечивается методом
TeleportTo[]. Вызовите его в выражении if и используйте квадратные скобки вместо круглых, потому чтоTeleportTo[] —это выражение с неоднозначным результатом. Операторifсоздаёт контекст, допускающий неоднозначность.Verseif(RootProp.TeleportTo[Destination.Translation, Destination.Rotation]): Print("Prop move successful") else: Print("Prop move failed")Аргументами метода
TeleportTo[]являются Перенос и Вращение. Оба они связаны со свойством Назначение.Вернитесь в редактор и перетащите объект окружения из Fortnite > Наборы > Объекты окружения в Каталог ресурсов. В данном руководстве мы используем объект окружения Береговой буй 02B, но отлично подойдёт и любой объект из папки «Объекты окружения».
Выберите устройство «Координатор цели» в окне Структура. На панели Сведения задайте значение RootProp для своего объекта окружения. В данном примере для параметра RootProp задано значение «Береговой буй 02B».
На панели Сведения разверните Назначение. Поскольку свойство Назначение имеет тип
transform, оно включает в себя Масштаб, Вращение и Перенос. Чтобы переместить объект окружения, достаточно изменить параметр Перенос, поэтому разверните его. Установите в поле, название которого заканчивается на X, значение 5000,0.При тестировании кода рекомендуется существенно изменять значения, чтобы эффект был очевиден. При небольших изменениях вы не сможете узнать, выполняется ли ваш код так, как ожидалось.
Verseusing { /Verse.org/Simulation } using { /Fortnite.com/Devices } using { /UnrealEngine.com/Temporary/SpatialMath } objective_coordinator_device<public> := class<concrete>(creative_device): @editable RootProp<public> : creative_prop = creative_prop{} # Where the marker will be moved toНажмите Verse > Создать код Verse > Запустить сеанс. Наконец, нажмите Начать игру. Вы увидите, как объект окружения перемещается.
Родительские элементы и структуры
Теперь у вас есть объект окружения, который перемещается по уровню. Однако наша конечная цель — это перемещение устройства «Указатель на карте», чтобы игроки могли использовать его в качестве путевой точки. Выполните следующие шаги, чтобы добавить постройку и устройство «Указатель на карте» на уровень и присоединить его к постройке.
Нажмите правой кнопкой мыши в Каталоге ресурсов, чтобы открыть контекстное меню.
Выберите Класс Blueprint в контекстном меню.
В окне Выбрать родительский класс нажмите Объект-здание.
В каталоге ресурсов появится новый класс Blueprint. Переименуйте его в BuildingProp.
Перетащите постройку на уровень. У этого объекта окружения нет сетки, поэтому будет отображаться только его графический ориентир.
В «Окне сборки» перетащите устройство «Указатель на карте» на постройку. Это сделает постройку родительским элементом для устройства «Указатель на карте». Теперь при перемещении постройки устройство «Указатель на карте» будет перемещаться вместе с ним.
Вы уже знаете, как создать устройство с помощью Verse, при этом можно создавать файлы Verse, которые не имеют собственных устройств.
Создайте новый файл Verse и назовите его objective_marker. Этот файл не будет создавать устройство. Вместо этого он будет содержать определение структуры
struct, доступной для устройства Verse, созданного вами ранее.Сначала объявите структуру
structс именем objective_marker. Она будет содержать две составляющих:RootPropиMapIndicator. Обе должны иметь спецификатор@editable.Verseobjective_marker<public> := struct<concrete>: @editable RootProp<public> : creative_prop = creative_prop{} @editable MapIndicator<public> : map_indicator_device = map_indicator_device{}
Методы расширения и именованные аргументы
Объявите единственный метод MoveMarker, который будет перемещать составляющую RootProp и присоединённое к ней устройство «Указатель на карте». Этот метод отражает две особенности языка: методы расширения и именованные аргументы.
(Marker : objective_marker).MoveMarker<public>(Transform : transform, ?OverTime : float)<suspends> : void =Методы расширения: вы добавляете метод
MoveMarker()в структуруobjective_marker. При объявлении метода расширения необходимо указать в круглых скобках идентификатор и тип, разделённые двоеточием. В данном случае:(Marker : objective_marker).Именованные аргументы: во втором аргументе
?OverTimeиспользуется символ?для указания того, что он должен быть именован при вызове функцииMoveMarker. Это позволяет любому разработчику, читающему или пишущему вызовMoveMarker, понять назначение аргумента типаfloat.
MoveMarker() будет вызывать один из двух методов с помощью API объекта окружения: TeleportTo[], который вы использовали ранее, или MoveTo(). Создайте блок if..else для проверки того, что параметр OverTime больше 0.0. Если это так, вызовите MoveTo(). В результате ваша цель переместится в следующее место за указанное вами время, вместо того чтобы телепортироваться мгновенно.
(Marker : objective_marker).MoveMarker<public>(Transform : transform, ?OverTime : float)<suspends> : void =
if (OverTime > 0.0):
Marker.RootProp.MoveTo(Transform.Translation, Transform.Rotation, OverTime)
else:
if:
Marker.RootProp.TeleportTo[Transform.Translation, Transform.Rotation]Если теперь вы скомпилируете код, всё должно получиться, но вы не увидите новое устройство в папке CreativeDevices в Каталоге ресурсов. Причина в том, что objective_marker является структурой, а не классом, который наследуется от creative_device.
Обновление устройства «Координатор цели»
Теперь, когда у вас есть новый тип, на который можно ссылаться, необходимо создать ссылку на устройство objective_coordinator_device.
Удалите свойство
RootPropи замените его свойством с именемPickupMarkerтипаobjective_marker. Это тип, который вы создали.Для
MoveMarker()требуется аргумент типаfloat. Создайте такой аргумент в виде редактируемого свойства с именемMoveTime.Удалите вызов
TeleportTo[]. Вместо этого вызовите методMoveMarker(), который вы создали дляobjective_marker. Ему требуется именованный аргумент?OverTime.Verseobjective_coordinator_device<public> := class<concrete>(creative_device): @editable PickupMarker<public> : objective_marker = objective_marker{} # Where the marker will be moved to @editable Destination<public> : transform = transform{} # How much time the marker should take to reach its new location
Скомпилируйте этот код и проверьте «Свойства» устройства «Координатор цели». Вы должны увидеть свойства PickupMarker и MoveTime, а свойство PickupMarker должно содержать RootProp и MapIndicator.
Выберите в поле RootProp значение BuildingProp, а в поле MapIndicator значение Устройство «Указатель на карте»
Скомпилируйте свой код и нажмите на кнопку Запустить сеанс. Вы должны увидеть маркер на мини-карте, который начнёт перемещаться вскоре после начала игры. Попробуйте поиграть со значениями
MoveTime, в том числе с0.0. Подумайте, какое перемещение лучше всего подходит для разных сценариев.
GetPlayers() и ActivateObjectivePulse()
Существует способ немного помочь игрокам в достижении следующей цели. Это так называемая пульсация цели, и, когда она активна, отображается пунктирная линия, движущаяся от игрока в направлении Устройства «Указатель на карте». Выполните следующие шаги, чтобы добавить пульсацию цели к устройству «Координатор цели».
Метод, необходимый для активации пульсации цели, называется ActivateObjectivePulse(), и он принимает единственный аргумент типа agent. Сначала создайте метод для получения экземпляра agent, представляющего вашего персонажа игрока.
Объявите функцию
FindPlayer(), определённую как<private>, с возвращаемым значениемvoid.Получите массив всех игроков на уровне с помощью
Self.GetPlayspace().GetPlayers(). Сохраните массив в переменной под названиемAllPlayers.VerseFindPlayer<private>() : void = AllPlayers := Self.GetPlayspace().GetPlayers()Чтобы получить ссылку на нужного игрока на уровне, присвойте первый элемент массива собственной переменной. Доступ к массиву — это выражение с неоднозначным результатом, поэтому поместите его в выражение
if.Verseif (FirstPlayer := AllPlayers[0]):Поскольку присвоение переменной значения
playerможет привести к ошибке, при ссылке на игрока в коде нужно использовать переменную типа option. Объявите опциональную переменную игрока?player. Она должна использоваться совместно с другими переменными-составляющими.Verseobjective_coordinator_device<public> := class<concrete>(creative_device): var PlayerOpt<private> : ?player = false @editable PickupMarker<public> : objective_marker = objective_marker{} # Where the marker will be moved to @editable Destination<public> : transform = transform{}Определите новую переменную и создайте блок
elseс выражениемPrint(), которое сообщит вам, если игрок не будет найден. Ваша функцияFindPlayer()готова.VerseFindPlayer<private>() : void = # Since this is a single player experience, the first player [0] # should be the only one available. AllPlayers := Self.GetPlayspace().GetPlayers() if (FirstPlayer := AllPlayers[0]): set PlayerOpt = option{FirstPlayer} Print("Player found")
В функции OnBegin() нужно внести ещё два изменения:
Вызовите функцию
FindPlayer().VerseOnBegin<override>()<suspends> : void = FindPlayer()После вызова
MoveMarker()используйте ещё одно выражениеif, чтобы установить опциональную переменную игрока на новую переменную, и передайте её в качестве аргумента вPickupMarker.MapIndicator.ActivateObjectivePulse()Verseif (FoundPlayer := PlayerOpt?): PickupMarker.MapIndicator.ActivateObjectivePulse(FoundPlayer)
Если вы запустите код сейчас, то увидите линию пульсации цели, направленную от персонажа к месту расположения маркера цели на уровне!
Полные сценарии
Objective_marker.verse
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Devices/CreativeAnimation }
objective_marker<public> := struct<concrete>:
# The prop that will be moved
@editable
RootProp<public> : creative_prop = creative_prop{}
Objective_coordinator_device.verse
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Playspaces }
using { /UnrealEngine.com/Temporary/SpatialMath }
objective_coordinator_device<public> := class<concrete>(creative_device):
var PlayerOpt<private> : ?player = false
@editable
Самостоятельная работа
Имейте в виду, что написанный вами код перемещения работает для любого объекта окружения. Если вы сделаете перемещаемый объект окружения родительским элементом устройства, это устройство будет перемещаться вместе с ним. Попробуйте перемещать другие объекты окружения и устройства и представьте себе другие игры, где их можно использовать.
Следующие шаги
Если вы используете это руководство для создания игры с механикой «подбери и доставь», далее вам нужно научиться создавать таймер обратного отсчёта.