В основе этого обучения лежат концепции из раздела Сохраняемая статистика игрока, поэтому для начала рекомендуем ознакомиться именно с этим разделом!
Таблицы лидеров — это основной элемент соревновательных игр, позволяющий игрокам продемонстрировать свои навыки и заявить о себе. Они помогают игрокам ощущать собственный прогресс и побуждают их постоянно возвращаться, чтобы увидеть, насколько выше в списке они поднялись.
Verse Persistence — это инструмент, который позволяет создавать такие таблицы лидеров и добавлять соревновательные элементы в игры. Из руководства по сохраняемой статистике игрока вы уже узнали, как можно отслеживать сохраняемые данные между игровыми сеансами, а также как изменять и обновлять эти данные с учётом различных событий. Теперь можно применить эти знания для создания полноценных локальных таблиц лидеров, сортировки статистики игроков и объединения всех этих элементов в гоночной игре!
Используемые возможности языка Verse
Класс: в этом примере создан сохраняемый класс Verse, отслеживающий группу показателей одного игрока.
Конструктор: это специальная функция, которая создаёт экземпляр связанного с ней класса.
weak_map: это простой ассоциативный массив, итерация по которому не производится. Сохраняемые данные Verse должны храниться в weak_map.
Подготовка уровня
В этом примере используются следующие объекты окружения и устройства:
3 устройства Рекламный щит: на них отображается статистика каждого игрока за всё игровое время, и вы будете сортировать игроков по набранным очкам, чтобы представить лучших игроков в лобби.
3 устройства Упоминание игрока: в сочетании с рекламными щитами эти устройства будут отображать имена лидеров, чтобы другие игроки знали, с кем стоит состязаться во время игры.
3 устройства Контрольная точка: это контрольные точки, через которые проезжают игроки, чтобы завершить гонку.
1 устройство Управление гонками: позволяет отслеживать моменты начала и завершения гонки игроками, а также начислять им очки с учётом места на финише.
1 устройство Генератор машин Bear: создаёт транспортное средство, которое вы будете использовать во время гонки, однако вы можете заменить его на любое другое транспортное средство, соответствующее тематике вашей игры.
Выполните следующие действия, чтобы настроить уровень:
Устройства «Рекламный щит» и «Упоминание игрока»
Для отображения статистики игроков нужно использовать комбинацию устройств «Рекламный щит» и «Упоминание игрока». На каждом рекламном щите будет отображаться статистика игрока за всё его игровое время, а устройство «Упоминание игрока» будет содержать визуальное представление об этом игроке. Чтобы добавить эти элементы, выполните следующие действия:
Добавьте три устройства Упоминание игрока на уровень и разместите их рядом друг с другом.
Выберите каждое устройство «Упоминание игрока» на панели Структура. На панели Сведения в разделе Пользовательские настройки выберите для параметра Пользовательский цвет тот цвет, который вы хотите использовать для обозначения в лобби первого, второго и третьего игроков, показавших лучшие результаты. В этом примере используются золотой, серебряный и бронзовый цвета.
Добавьте три устройства Рекламный щит на уровень и разместите их напротив каждого устройства «Упоминание игрока». В начале игры мы добавим в каждое устройство статистику игрока с помощью Verse.
Устройства «Контрольная точка», «Генератор машин Bear» и «Управление гонками»
Поскольку мы с вами разрабатываем гоночную игру, нужно добавить состязательные элементы. Вам также понадобятся контрольные точки для проезда и устройство «Управление гонками», которое будет управлять гонкой во время игры. Чтобы добавить эти элементы, выполните следующие действия:
Добавьте три устройства Контрольная точка в гонках на уровень. Расположите их в том порядке, в котором вы хотите, чтобы игроки через них проезжали. Проверьте, чтобы на панели Структура Номер контрольной точки каждой контрольной точки соответствовал порядку прохождения игроками контрольных точек.
Добавьте одно устройство Управление гонками на уровень. Так вы сможете управлять гонкой и направлять игроков к контрольным точкам. Необходимо перехватывать событие
RaceCompletedEvent()из этого устройства, чтобы знать, когда игрок заканчивает гонку.Добавьте одно устройство Генератор машин Bear на уровень. Транспортное средство добавлять необязательно, однако в этом руководстве мы используем пикап, чтобы воссоздать Шаблон гоночной трассы и предоставить игрокам средство передвижения.
Изменение статистической таблицы
В этом примере используется изменённая версия файла player_stats_table из Сохраняемой статистики игрока. Этот файл будет похож на файл из того примера, однако в нём будут серьёзные отличия, из-за которых процесс реализации тоже будет изменён.
Выполните следующие действия, чтобы создать таблицу статистики игрока:
В классе
player_stats_table:Удалите показатель
Losses.Измените показатель
ScoreнаPoints.Verse# Tracks different persistable stats for each player. player_stats_table<public>:= class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The Points of a player. Points<public>:int = 0 # The number of Wins for a player.
Измените функцию конструктора
MakePlayerStatsTable()в вашем файле так, чтобы в ней отражалась обновлённая статистика.Verse# Creates a new player_stats_table with the same values as the previous player_stats_table. MakePlayerStatsTable<constructor>(OldTable:player_stats_table)<transacts> := player_stats_table: Version := OldTable.Version Points := OldTable.Points Wins := OldTable.WinsДобавьте новую структуру
player_and_statsв файл player_stats_table.verse. Эта структура содержит ссылку наplayerи его классplayer_stats_table, что позволяет вам использовать данные каждого из них в функциях без необходимости их повторного извлечения. Готовая структураplayer_and_statsдолжна выглядеть следующим образом:Verse# Structure for passing a player and their stats as arguments. player_and_stats<public> := struct: Player<public>:player StatsTable<public>:player_stats_table
Управление статистикой
Для управления изменениями в статистике игроков и регистрацией такой статистики мы будем использовать диспетчер файлов — как и в случае с Сохраняемой статистикой игрока.
Чтобы создать изменённый файл player_stats_manager, выполните действия, описанные ниже.
Измените сигнатуру функции
InitializeAllPlayers()иInitializePlayer()наInitializeAllPlayerStats()иInitializePlayerStat(). Эти имена лучше отражают их отношение к функцииGetPlayerStat(). Ваша обновлённая функция должна выглядеть следующим образом:Verse# Initialize stats for all current players. InitializeAllPlayerStats<public>(Players:[]player):void = for (Player : Players): InitializePlayerStat(Player) # Initialize stats for the given player. InitializePlayerStat<public>(Player:player):void= if: not PlayerStatsMap[Player] set PlayerStatsMap[Player] = player_stats_table{}Измените сигнатуру функции
AddScore()наAddPoints(). Затем удалите функциюAddLosses(), поскольку переменнаяplayer_stats_tableбольше не содержит это значение. Файлplayer_stats_managerв конечном итоге должен выглядеть следующим образом:Verse# This file handles the code for initializing, updating, and returning player_stats_tables # for each player. It also defines an abstract stat_type class to use for updating stats, and the # StatType module to use when displaying stats. using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Return the player_stats_table for the provided Agent. GetPlayerStats<public>(Agent:agent)<decides><transacts>:player_stats_table=
Создание таблиц лидеров игроков
Для отображения данных игроков в таблице лидеров необходимо следующее. Нужно найти способ обновлять текст на рекламных щитах и игроков и устройствах «Упоминание игрока». А ещё эти устройства нужно сортировать, ведь нужно сделать так, чтобы имена лучших игроков выделялись среди всех в таблице лидеров. Описанные функции имеют схожую цель — они должны изменять устройства на уровне, поэтому рекомендуем сгруппировать их в общий файл.
Для создания функций, которые будут обновлять устройства на уровне, выполните следующие действия:
Создайте новый файл Verse с именем player_leaderboards.verse. В нём будут храниться функции, общие для обновления таблицы лидеров на уровне.
Для вывода текста на рекламном щите будем использовать сообщение, в которое можно передавать аргументы. Создайте новое сообщение с названием
StatsMessage, которое принимает значенияCurrentPlayer,PointsиWinsтипаmessageи возвращает объединённый текст в видеmessage.Verse# The message to display on the stats billboard. StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message= "{CurrentPlayer}:\n{Points}\n{Wins}"Добавьте ещё три переменные
message, по одной для каждого из входных данных дляStatsMessage. СообщениеPlayerTextпринимает агентаAgent, сообщениеPointsTextпринимает количество очков этого агента, а сообщениеWinsTextпринимает количество побед этого агента.StatsMessageсоздаст сообщение из всего вышеописанного для наглядного отображения ваших данных на уровне.Verse# The message to display on the stats billboard. StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message= "{CurrentPlayer}:\n{Points}\n{Wins}" PlayerText<localizes>(CurrentPlayer:agent):message = "Player {CurrentPlayer}" PointsText<localizes>(Points:int):message = "Total Points {Points}" WinsText<localizes>(Wins:int):message = "{Wins} Total Wins"Чтобы обновить рекламный щит, вызовите функцию
UpdateStatsBillboard()из руководства «Сохраняемая статистика игрока». Эта функция определена в отдельном файле от устройства Verse, поэтому нужно добавитьStatsBillboardв качестве дополнительного аргумента, чтобы указать, какой рекламный щит нужно будет обновлять.Verse# Updates the given billboard device to display the stats of the given player. UpdateStatsBillboard<public>(Player:agent, StatsBillboard:billboard_device):void=Сначала получите статистику игрока, переданную в качестве аргумента, с помощью
GetPlayerStats[]. Ссылка наplayer_stats_managerне потребуется, поскольку он больше не является отдельным классом. Затем создайте новое сообщениеStatsMessageс помощью игрока, а такжеPointsиWinsиз его статистикиCurrentPlayerStats. Наконец, вызовитеSetText()дляStatsBillboard, чтобы обновить текст рекламного щита на уровне. Готовая функцияUpdateStatsBillboard()должна выглядеть следующим образом:Verse# Updates the given billboard device to display the stats of the given player. UpdateStatsBillboard<public>(Player:agent, StatsBillboard:billboard_device):void= if: CurrentPlayerStats := GetPlayerStats[Player] then: PlayerStatsText := StatsMessage( PlayerText(Player), PointsText(CurrentPlayerStats.Points), WinsText(CurrentPlayerStats.Wins)) StatsBillboard.SetText(PlayerStatsText)
Сортировка игроков и отображение имени лучшего игрока
Прежде чем продолжить, подумайте о том, как вы хотите выполнять сортировку в этих рекламных щитах. Вы хотите, чтобы в верхней строчке был игрок, набравший наибольшее количество очков, или игрок с наибольшим количеством побед? Может, вы хотите сортировать игроков по их статистике? Вам нужен метод, который будет обрабатывать эти запросы, а также алгоритм сортировки. Используя алгоритм сортировки и функцию сравнения, вы сможете указать, по каким критериям вы хотите сортировать данные. Вы также сможете отсортировать рекламные щиты и устройства «Упоминание игроков», чтобы отобразить имена лучших игроков. В этом примере используется алгоритм Сортировки с объединением, однако вы можете реализовать свой собственный алгоритм.
Выполните следующие действия, чтобы добавить функции сравнения и сортировки в рекламные щиты и завершить обновление устройств на уровне.
В файле
player_stats_tableопределим функции сравнения для каждого из показателей. Каждая из них принимает в качестве аргументов структурыLeftиRightтипаplayer_and_statsи сравнивает их по значениям конкретного показателя. Эти функции имеют модификаторы<decides><transacts>, поэтому, если сравнение не удастся, функция также завершится неудачно. Например, вы получите сообщение о том, чтоLeftменьше, чемRight. Добавьте новую функциюMorePointsComparison()в файл player_stats_table.verse. Эта функция проверяет, больше лиLeft.Points, чемRight.Points, и завершается с ошибкой, если это не так. В случае успеха она возвращаетLeft`.Verse# Returns Left if Left has greater Points than Right. MorePointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:Left= Left.StatsTable.Points > Right.StatsTable.Points LeftСоздайте ещё три копии этой функции — одна будет использоваться для сравнения с целью определения меньшего числа очков, а две — для сравнения числа побед. Ваши функции сравнения должны выглядеть следующим образом:
Verse# Returns Left if Left has greater Points than Right. MorePointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:player_and_stats= Left.StatsTable.Points > Right.StatsTable.Points Left # Returns Left if Left has less Points than Right. LessPointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:player_and_stats= Left.StatsTable.Points < Right.StatsTable.Points LeftДобавьте алгоритм Сортировки с объединением. Вы можете поместить его в отдельный файл или модуль и протестировать такой алгоритм на предоставленном тестовом файле.
Теперь в
player_leaderboardsдобавим новую функциюUpdateStatsBillboards(). Эта функция принимает массив агентов и массив рекламных щитов, сортирует их и вызываетUpdateStatsBillboard()для обновления каждого рекламного щита на уровне.Verse# Update the stats billboards by sorting them based on the amount of lifetime points # each player has. UpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void=В
UpdateStatsBillboards()инициализируем новую переменную массиваplayer_and_statsс именемPlayerAndStatsArray. Присваиваем ей результат выраженияfor. В этом выраженииforдля каждогоagentполучаемplayerдля данногоagentи получаем егоplayer_stats_tableс помощьюGetPlayerStats[]. Затем возвращаем структуруplayer_and_stats, построенную на основеplayerи его таблицы статистики.VerseUpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats: Player := Player StatsTable := PlayerStatsДля сортировки
PlayerAndStatsArrayинициализируем новую переменнуюSortedPlayersAndStatsрезультатом вызоваMergeSort(), передав массив иMorePointsComparison. После сортировки в выраженииforперебираем все элементы вSortedPlayerAndStats, сохраняя индекс элемента в переменнойPlayerIndex. ИспользуемPlayerIndexдля обращения к определённому элементу массиваStatsBillboards, а затем вызываемUpdateStatsBillboard, передав игрока и рекламный щит для обновления. Готовая функцияUpdateStatsBillboards()должна выглядеть следующим образом:Verse# Update the stats billboards by sorting them based on the amount of lifetime points # each player has. UpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats:Для обновления устройств «Упоминание игрока» воспользуемся очень похожей функцией, которая называется
UpdatePlayerReferences(). Эта функция принимает массивplayer_reference_deviceвместо рекламных щитов и вместо вызоваUpdateStatsBillboard()в конце она вызываетRegister()для устройства «Упоминание игрока» применительно к каждому игроку. Скопируйте свой кодUpdateStatsBillboard()в новую функциюUpdatePlayerReferences(), внеся изменения, указанные выше. Готовая функцияUpdatePlayerReferences()должна выглядеть следующим образом:Verse# Update the player references devices by sorting them based on the amount # of lifetime points each player has. UpdatePlayerReferences<public>(Players:[]player, PlayerReferences:[]player_reference_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats:
Таблицы лидеров игроков на уровне
Теперь, когда всё настроено, пора показать игроков! Создадим устройство, которое будет присваивать очки игрокам при их взаимодействии с кнопкой, и отсортируем устройства «Упоминание игрока» и рекламные щиты, чтобы лучшие игроки оказались впереди по центру. Выполните следующие действия, чтобы создать устройство Verse для тестирования таблиц лидеров на вашем уровне:
Создайте новое устройство Verse и назовите его player_leaderboards_example. Порядок действий см. в разделе «Создание собственного устройства с помощью Verse».
В начале определения класса
player_leaderboards_exampleдобавьте следующие поля:Редактируемый массив устройств «Упоминание игрока»
PlayerReferences. Эти устройства обеспечивают визуальное представление каждого игрока в гонке.Verse# Visual representations of each player. @editable PlayerReferences:[]player_reference_device = array{}Редактируемый массив устройств «Рекламный щит»
Leaderboards. Они показывают статистику каждого игрока на рекламном щите на уровне.Verse# Billboards that display each player's stats. @editable Leaderboards:[]billboard_device = array{}Редактируемое устройство «Управление гонками»
RaceManager. Подпишемся на события от устройства «Управление гонками», чтобы знать, когда игрок заканчивает гонку.Verse# Tracks when players complete a race, with the players in the first spot being awarded a win. @editable RaceManager:race_manager_device = race_manager_device{}Редактируемая целочисленная переменная
PlacementRequiredForWin. Это место игрок должен занять для присуждения ему победы.Verse# The placement of a player must be at or below to award a win. @editable PlacementRequiredForWin:int = 1Редактируемый массив целых чисел
PointsPerPlace. Это количество очков, которое каждый игрок получает в зависимости от его места.Verse# The number of points a player in each place earns. # Adjust this to award your players the desired amount of score # based on their placement. @editable PointsPerPlace:[]int = array{5, 3, 1}Целочисленная переменная
CurrentFinishOrder. Это место игрока, который завершил гонку только что.Verse# The spot of the player who just finished the race. # The first three players to finish the race will be awarded a win. var CurrentFinishOrder:int = 0
Начисление очков в зависимости от места
Как только игрок завершит гонку, нужно будет обновить его статистику с учётом его места. Игроки, занявшие высокие места, должны получить больше очков, а те из них, кто показал лучшие результаты, должны быть объявлены победителями.
Выполним следующие действия для начисления очков игрокам при завершении гонки:
Чтобы решить эту задачу, добавим новую функцию
RecordPlayerFinish()в определение классаplayer_leaderboards_example. Эта функция принимает игрока, которому необходимо начислить очки, как параметр.Verse# When a player finishes the race, award them points based on their placement, and award them a win if # their placement was better than the PlacementRequiredForWin. RecordPlayerFinish(Player:agent):void=В
RecordPlayerFinish()получим место этого игрока, получив текущее значениеCurrentFinishOrderв новой переменнойintс именемPlayerFinishOrder. Затем увеличимCurrentFinishOrder, чтобы следующий финиширующий игрок не оказался на том же месте.VerseRecordPlayerFinish(Player:agent):void= PlayerFinishOrder:int = CurrentFinishOrder set CurrentFinishOrder += 1А теперь пора начислять очки. Чтобы знать, сколько очков нужно присвоить определённому игроку, в выражении
ifобратимся к массивуPointsPerPlaceс помощьюPlayerFinishOrder. Затем вызовемAddPoints()для начисления игроку такого количества очков.Verseset CurrentFinishOrder += 1 if: PointsToAward := PointsPerPlace[PlayerFinishOrder] then: AddPoints(Player, PointsToAward)Если игрок достаточно опередил остальных, чтобы выиграть, нужно отразить победу в его таблице статистики. В другом выражении
ifубедитесь, что значениеPlayerFinishOrderоказалось меньше значенияPlacementRequiredToWin. При выполнении данного условия вызываемAddWin(), передавая соответствующего игрока и присуждаемое ему место. Готовая функцияRecordPlayerFinish()должна выглядеть следующим образом:Verse# When a player finishes the race, award them points based on their placement, and award them a win if # their placement was better than the PlacementRequiredForWin. RecordPlayerFinish(Player:agent):void= PlayerFinishOrder:int = CurrentFinishOrder set CurrentFinishOrder += 1 if: PointsToAward := PointsPerPlace[PlayerFinishOrder] then: AddPoints(Player, PointsToAward)
Ожидание завершения гонки игроками
Запись статистики настроена, и теперь нужно определять момент завершения игроком гонки, чтобы эту статистику можно было обновить. Для этого будем ожидать RaceCompletedEvent() диспетчера гонки. Это событие возникает, когда какой-либо из игроков завершает гонку, поэтому его нужно прослушивать постоянно в асинхронной функции.
Добавим новую функцию
WaitForPlayerToFinishRace()в определение классаplayer_leaderboards_example. Эта функция принимает игрока и ожидает момента, когда он завершит гонку.Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void=В функции
WaitForPlayerToFinishRace()организуем два цикла в выраженииrace. В первом будем ожидать завершения игроком гонки, а во втором обработаем ситуацию, когда игрок выходит из сеанса до финиша. Если игрок выйдет из игры, цикл уже не нужно будет выполнять бесконечно, а потому нужно решить, как его прервать.Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void= race: # Waiting for this player to finish the race and then record the finish. loop: # Waiting for this player to leave the game. loop:В первом цикле ожидаем
RaceManager.RaceCompletedEventи сохраняем результат в переменнойFinishingPlayer. Так как это событие возникает всегда, когда один из игроков завершает гонку, важно, чтобы сохранённый игрок оказался тем игроком, которого мы отслеживаем. СравниваемFinishingPlayerс игроком, который отслеживается в этом цикле. Если игроки совпадают, передаём игрока вRecordPlayerFinish()и прерываем цикл.Verse# Waiting for this player to finish the race and then record the finish. loop: FinishingPlayer := RaceManager.RaceCompletedEvent.Await() if: FinishingPlayer = Player then: RecordPlayerFinish(Player) breakВо втором цикле ожидаем событие игрового пространства
PlayerRemovedEvent(). Как и раньше, получаем игрока, который только что вышел из игры, и сохраняем его в переменнойLeavingPlayer. Если только что вышедший из игры игрок совпадает с ожидаемым в цикле, прерываем цикл. Готовая функцияWaitForPlayerToFinishRace()должна выглядеть следующим образом:Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void= race: # Waiting for this player to finish the race and then record the finish. loop: FinishingPlayer := RaceManager.RaceCompletedEvent.Await() if: FinishingPlayer = Player then: RecordPlayerFinish(Player)
Связывание всех элементов
Функции настроены, и теперь пора связать их с устройствами и запустить гонку!
Чтобы связать логику с устройствами, выполните следующие шаги:
В
OnBegin()получите всех игроков в игровом пространстве с помощьюGetPlayers(). Передайте этот массив вInitializeAllPlayerStats(), чтобы настроитьplayer_stats_tablesдля каждого из них.Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Get the players in the current race and create a player_stat_table # for each of them. Players := GetPlayspace().GetPlayers() InitializeAllPlayerStats(Players)Вызовите функцию
UpdateStatsBillboards(), передав массивыPlayersиLeaderboardsдля обновления имеющихся на уровне рекламных щитов в соответствии с текущими данными каждого игрока. Затем вызовите функциюUpdatePlayerReferences(), чтобы обновить имеющиеся на уровне устройства «Упоминание игрока» в соответствии с результатами игроков. Наконец, в выраженииforсоздайте экземпляр функцииWaitForPlayerToFinishRace()для каждого игрока. Готовая функцияOnBegin()должна выглядеть следующим образом:Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Get the players in the current race and create a player_stat_table # for each of them. Players := GetPlayspace().GetPlayers() InitializeAllPlayerStats(Players) UpdateStatsBillboards(Players, Leaderboards) UpdatePlayerReferences(Players, PlayerReferences) # Wait for all players to finish the race.Сохраните свой код и скомпилируйте его.
Перетащите устройство player_leaderboards_example на уровень. Включите устройства «Упоминание игрока» в массив PlayerReferences в соответствующем порядке. Устройство «Упоминание игрока» с первым индексом должно соответствовать лучшему игроку, со вторым индексом — второму игроку и т. д. То же самое проделайте для рекламных щитов, не забывая о том, что они должны соответствовать устройствам «Упоминание игрока». Не забудьте также назначить устройство «Управление гонками»!
Тестирование сохраняемых таблиц лидеров
Вы можете протестировать сохраняемые данные в сеансе редактирования, но они будут сброшены при выходе из сеанса и его перезапуске. Чтобы данные сохранялись от сеанса к сеансу, нужно запустить сеанс игрового теста и изменить некоторые настройки в разделе Настройки острова. Информация о настройке острова для тестирования сохраняемых данных как в режиме редактирования, так и в игровом тесте приведена в разделе Тестирование с сохраняемыми данными. Кроме того, нужно изменить некоторые настройки в разделе «Настройки острова». Информация о настройке острова для тестирования сохраняемых данных как в режиме редактирования, так и в игровом тесте приведена в разделе Тестирование с сохраняемыми данными.
После входа в сеанс в игровом тесте уровня игроки, завершающие гонку, должны получать очки с учётом их места. Им должна присуждаться победа, если их место достаточно высоко, и такая статистика должна сохраняться от одного игрового сеанса к другому. Игроки и их статистика должны сортироваться таким образом, чтобы игрок с наибольшим количеством очков находился на первом месте.
Самостоятельная работа
В данном руководстве вы узнали, как создавать таблицы лидеров, в которых отображается сохраняемая статистика по игрокам на уровне. Вы также узнали, как сортировать и обновлять эти таблицы лидеров, благодаря чему всем будет понятно, кто лидирует. Попробуйте применить в собственной игре знания, полученные в этом уроке, и покажите лучших в вашей игре!
Полный код
player_stats_table.verse
# This file defines a player_stats_table, a collection of persistable player statistics.
# It also contains functions to compare stats tables by each of the stats to order players
# when sorting.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Structure for passing a player and their stats as arguments.
player_and_stats<public> := struct:
player_leaderboards.verse
# This file contains the code that updates the billboards, player references, and UI on the island
# to display a player's stats from their player stats table. It also handles adding wins and points to a
# player's stats table.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation}
# The message to display on the stats billboard.
StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message=
"{CurrentPlayer}:\n{Points}\n{Wins}"
player_stats_manager.verse
# This file handles the code for initializing, updating, and returning player_stats_tables
# for each player. It also defines an abstract stat_type class to use for updating stats, and the
# StatType module to use when displaying stats.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Return the player_stats_table for the provided Agent.
GetPlayerStats<public>(Agent:agent)<decides><transacts>:player_stats_table=
player_leaderboards_example.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { PlayerLeaderboard }
# See https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse for how to create a verse device.
# A Verse-authored creative device that can be placed in a level
player_leaderboards_example := class(creative_device):
# Visual representations of each player.