Назад
Узнайте, как мы улучшили шаблон творческого режима Fortnite «Создание гоночной трассы» с помощью Verse Persistence и не только.
Разработчики Fortnite
С появлением Verse Persistence у нас появилась возможность оптимизировать под UEFN шаблон творческого режима Fortnite «Создание гоночной трассы». Мы не только добавили видеоролики и обновили ландшафт, но и заменили триггеры на код Verse. В этой статье вы узнаете, как нам удалось этого добиться. Встречайте: Verse Persistence в шаблоне «Создание гоночной трассы»!
Шаблон «Создание гоночной трассы» был изначально спроектирован, чтобы помочь игрокам создавать треки с интересными и удобными функциями, используя ранее выпущенные ресурсы для гоночных трасс.
По мере обновления редактора и развития его возможностей для творчества мы решили более комплексно подойти к шаблону и внесли в карту множество изменений. Давайте взглянем на некоторые из них, нагляднее всего демонстрирующие широкие возможности UEFN.
Устаревший цикл смены дня и ночи был заменён более продвинутым освещением из четвёртой главы «Королевской битвы» Fortnite. Мы использовали технологию Lumen, которая создаёт более мягкие тени и реалистичное глобальное освещение. Чтобы придать трассе визуальной сложности, мы также добавили такие элементы, как водопад.
Благодаря Verse Persistence нам удалось найти решение, с помощью которого пользовательская информация сохраняется между игровыми сеансами, а система может отслеживать статистику игроков за всё время и создавать локальные списки лидеров.
Мы хотели создать систему, которая бы обновляла рекордное время прохождения круга после каждого круга, а также регистрировала очки игроков и победы после финиша.
С обновлением рекордного времени круга проблем не возникло: событие LapCompletedEvent устройства «Управление гонками» отслеживает, когда игрок завершает круг. В начале гонки мы запускаем устройство «Таймер» — оно действует для каждого игрока. Функция WaitForPlayerToFinishLap запускается, когда игрок завершает круг, затем высчитывает время круга, обновляет таблицу статистики и сбрасывает таймер, чтобы начать регистрировать данные для следующего круга.
Чтобы решить эту проблему, наша команда воспользовалась функцией ArraySync. ArraySync вызывает асинхронную функцию для каждого переданного элемента в массиве, а затем ждёт выполнения всех функций. Передав массив игроков и функцию WaitForPlayerToFinishRace, мы можем вызывать как функцию для каждого из них, так и дожидаться её выполнения для всех гонщиков.
Этот позволило нам присуждать игрокам очки и победы в зависимости от их места при завершении гонки, а затем соответствующим образом обновлять таблицы статистики. Если функция ArraySync завершилась, значит все игроки достигли финиша и игра закончена.
Поскольку у нас уже есть сохраняемая статистика каждого игрока, мы можем извлечь эти данные и разместить их на баннере. Мы добавили устройства «Рекламный щит» и «Упоминание игрока» в зону ожидания для каждого игрока. Таким образом, каждый гонщик может видеть свои текущие показатели и экипировку. Нам всё ещё предстояло выяснить, как отсортировать всех игроков, исходя из их результатов.
Для этого мы использовали алгоритм «Сортировка с объединением». Это стандартный алгоритм сортировки с последовательным разделением, который делит массив на два, сортирует каждый из них по отдельности, а затем объединяет их. Мы также добавили в алгоритм возможность передавать функцию сравнения и создали функции сравнения для каждого показателя игрока.
Если нам требуется отсортировать игроков, мы можем извлечь данные из таблицы статистики, добавить их в массив, и передать их и функцию сравнения в алгоритм «Сортировка с объединением». Таким образом, выбирая разные функции сравнения, мы можем получить массив игроков, отсортированных по любым параметрам. В новый шаблон добавлен алгоритм «Сортировка с объединением», а также файл для тестирования. Вы в любой момент можете протестировать его и отредактировать по своему желанию.
Механизмы сортировки выбраны. Списки лидеров готовы. Во время первого раунда игроки, их параметры и рекламные щиты появляются в зоне ожидания. Мы сортируем данные всех игроков по количеству очков и отображаем статистику на баннере перед ними. Теперь они могут изучить обстановку на уровне до начала гонки и выяснить, за какими противниками нужно следить в оба, чтобы выиграть.
Продолжайте практиковаться, и однажды ваше имя займёт первую строчку в списке лидеров!
Для этого мы создали переменную слабого ассоциативного массива игроков CircuitInfo. Она содержит всю информацию, которую необходимо сбросить, когда гонка заканчивается или игрок покидает сеанс.
С помощью CircuitInfo мы можем легко понять, какие данные нужно сбросить (информацию о круге), а какую — сохранять между сеансами (статистику игроков).
Для каждого игрока мы регистрируем в переменной CircuitInfo следующую информацию:
С помощью функции OnBegin устройства Verse, которое запускается в начале каждого раунда, мы определяем, какой раунд сейчас идёт, перебирая всех активных игроков и получая наибольшее значение последнего завершённого раунда из сохранённых данных гонщиков. Мы запускаем этот процесс единожды за раунд и регистрируем показатели раунда в переменную слабого ассоциативного массива сеанса. Таким образом, код Verse может получить доступ к значению в любой момент без необходимости повторного вычисления.
Когда игрок завершает гонку (для этого ждём событие RaceCompletedEvent в устройстве «Управление гонками»), мы регистрируем финишную позицию и текущий раунд в переменной слабого ассоциативного массива CircuitInfo, связанной с игроком. Чтобы сбросить эти данные, необходимы следующие условия:
В обновлённом шаблоне мы решили вставить видеоролик начала гонок и заменили изначальное устройство на Sequencer. Благодаря этому инструменту нам удалось добавить в сцену разные камеры, элементы интерфейса и динамический вид сверху, который подстраивается под количество активных игроков.
Как и в случае с триггером импульса, мы подключили устройства к последовательности в важные моменты и знаем, когда нужно отображать счёт следующего игрока, а когда — пропускать видеоролик.
Нам не терпится увидеть, как нововведения могут изменить этот шаблон. А пока скачивайте шаблон, знакомьтесь с его тонкостями и переносите технический функционал в свои проекты. Найти его в UEFN можно на вкладке шаблонов. Будем рады видеть ваши трассы, списки лидеров и другие интересные детали!
Шаблон «Создание гоночной трассы» был изначально спроектирован, чтобы помочь игрокам создавать треки с интересными и удобными функциями, используя ранее выпущенные ресурсы для гоночных трасс.
По мере обновления редактора и развития его возможностей для творчества мы решили более комплексно подойти к шаблону и внесли в карту множество изменений. Давайте взглянем на некоторые из них, нагляднее всего демонстрирующие широкие возможности UEFN.
Визуальное оформление
Режим формирования ландшафта в UEFN позволил нам вернуться к истокам автоспорта и с помощью новых инструментов редактирования создать трассу для бездорожья. Горы, которые в первоначальном шаблоне были созданы при помощи материалов камней, уступили место более естественному дизайну ландшафта.Устаревший цикл смены дня и ночи был заменён более продвинутым освещением из четвёртой главы «Королевской битвы» Fortnite. Мы использовали технологию Lumen, которая создаёт более мягкие тени и реалистичное глобальное освещение. Чтобы придать трассе визуальной сложности, мы также добавили такие элементы, как водопад.
Verse Persistence: улучшенный список лидеров
На оригинальной карте устройство «Упоминание игрока» отображало на башне список игроков и полученные ими очки, а при выходе из игры эти данные стирались.Благодаря Verse Persistence нам удалось найти решение, с помощью которого пользовательская информация сохраняется между игровыми сеансами, а система может отслеживать статистику игроков за всё время и создавать локальные списки лидеров.
Статистика игроков
Мы разработали класс таблицы, который сохраняет статистику пользователей и отслеживает победы за всё время, рекордное время прохождения круга и очки игрока за отдельную гонку. Наша команда также добавила сохраняемый слабый ассоциативный массив PlayerStatsMap, в котором игроки привязываются к таблицам статистики. Именно эта функция позволяет этим данным существовать между раундами и сеансами. Мы также создали класс диспетчера статистики, который запускает процесс сбора статистики для каждого игрока, извлекает её и обновляет.Мы хотели создать систему, которая бы обновляла рекордное время прохождения круга после каждого круга, а также регистрировала очки игроков и победы после финиша.
С обновлением рекордного времени круга проблем не возникло: событие LapCompletedEvent устройства «Управление гонками» отслеживает, когда игрок завершает круг. В начале гонки мы запускаем устройство «Таймер» — оно действует для каждого игрока. Функция WaitForPlayerToFinishLap запускается, когда игрок завершает круг, затем высчитывает время круга, обновляет таблицу статистики и сбрасывает таймер, чтобы начать регистрировать данные для следующего круга.
Победы и счёт
Отслеживать победы и счёт оказалось намного сложнее. Мы могли воспользоваться схожей функцией WaitForPlayerToFinishRace и дождаться события RaceCompletedEvent устройства «Управление гонками», чтобы понимать, когда один из игроков достигает финиша. Однако нам хотелось, чтобы игра заканчивалась, когда финишируют все гонщики. Добиться этого с помощью устройства «Управление гонками» было невозможно.Чтобы решить эту проблему, наша команда воспользовалась функцией ArraySync. ArraySync вызывает асинхронную функцию для каждого переданного элемента в массиве, а затем ждёт выполнения всех функций. Передав массив игроков и функцию WaitForPlayerToFinishRace, мы можем вызывать как функцию для каждого из них, так и дожидаться её выполнения для всех гонщиков.
Этот позволило нам присуждать игрокам очки и победы в зависимости от их места при завершении гонки, а затем соответствующим образом обновлять таблицы статистики. Если функция ArraySync завершилась, значит все игроки достигли финиша и игра закончена.
Отображение результатов
После того, как процесс регистрации показателей был налажен, мы стали думать, как отображать игрокам всю собранную статистику. Нам хотелось создать такой список лидеров, в котором все игроки были отсортированы по количеству очков за все сеансы. Это позволило бы поместить лучших игроков на верхние места таблицы, которая видна всем гонщикам.Поскольку у нас уже есть сохраняемая статистика каждого игрока, мы можем извлечь эти данные и разместить их на баннере. Мы добавили устройства «Рекламный щит» и «Упоминание игрока» в зону ожидания для каждого игрока. Таким образом, каждый гонщик может видеть свои текущие показатели и экипировку. Нам всё ещё предстояло выяснить, как отсортировать всех игроков, исходя из их результатов.
Для этого мы использовали алгоритм «Сортировка с объединением». Это стандартный алгоритм сортировки с последовательным разделением, который делит массив на два, сортирует каждый из них по отдельности, а затем объединяет их. Мы также добавили в алгоритм возможность передавать функцию сравнения и создали функции сравнения для каждого показателя игрока.
Если нам требуется отсортировать игроков, мы можем извлечь данные из таблицы статистики, добавить их в массив, и передать их и функцию сравнения в алгоритм «Сортировка с объединением». Таким образом, выбирая разные функции сравнения, мы можем получить массив игроков, отсортированных по любым параметрам. В новый шаблон добавлен алгоритм «Сортировка с объединением», а также файл для тестирования. Вы в любой момент можете протестировать его и отредактировать по своему желанию.
Механизмы сортировки выбраны. Списки лидеров готовы. Во время первого раунда игроки, их параметры и рекламные щиты появляются в зоне ожидания. Мы сортируем данные всех игроков по количеству очков и отображаем статистику на баннере перед ними. Теперь они могут изучить обстановку на уровне до начала гонки и выяснить, за какими противниками нужно следить в оба, чтобы выиграть.
Продолжайте практиковаться, и однажды ваше имя займёт первую строчку в списке лидеров!
Порядок игроков на стартовой линии
На карте творческого режима Fortnite игроки размещаются на стартовой линии в случайном порядке. Чтобы побудить гонщиков стремиться к верхним местам таблицы лидеров, мы установили порядок игроков в зависимости от их финишной позиции в предыдущем раунде.Показатели раундов
Порядок игроков и показатели раундов должны сохраняться от раунда к раунду, но не между игровыми сеансами, как в случае с сохраняемыми данными для списка лидеров. Переменная слабого ассоциативного массива в Verse, используемая для сеансов, обновляет данные каждый раунд. Нам нужно сохранить эти показатели для каждого игрока и сбросить их после завершения игры.Для этого мы создали переменную слабого ассоциативного массива игроков CircuitInfo. Она содержит всю информацию, которую необходимо сбросить, когда гонка заканчивается или игрок покидает сеанс.
С помощью CircuitInfo мы можем легко понять, какие данные нужно сбросить (информацию о круге), а какую — сохранять между сеансами (статистику игроков).
Для каждого игрока мы регистрируем в переменной CircuitInfo следующую информацию:
- позицию на финише;
- последний завершённый раунд;
логику для каждого раунда.
Нам нужно понять, для какого раунда применять ту или иную логику (например, выбор стартовых позиций по итогам предыдущих раундов), а также когда сбрасывать данные игроков. Пока у нас нет API, который бы подсчитывал каждый раунд — поэтому нам необходимо записывать его результаты в сохраняемые данные для каждого игрока.С помощью функции OnBegin устройства Verse, которое запускается в начале каждого раунда, мы определяем, какой раунд сейчас идёт, перебирая всех активных игроков и получая наибольшее значение последнего завершённого раунда из сохранённых данных гонщиков. Мы запускаем этот процесс единожды за раунд и регистрируем показатели раунда в переменную слабого ассоциативного массива сеанса. Таким образом, код Verse может получить доступ к значению в любой момент без необходимости повторного вычисления.
Когда игрок завершает гонку (для этого ждём событие RaceCompletedEvent в устройстве «Управление гонками»), мы регистрируем финишную позицию и текущий раунд в переменной слабого ассоциативного массива CircuitInfo, связанной с игроком. Чтобы сбросить эти данные, необходимы следующие условия:
- Игрок покидает остров после начала игры. Мы подписались на PlayerRemovedEvent игрового пространства, чтобы вызвать функцию ResetCircuitInfo после того, как гонщик выйдет из сеанса.
- В начале каждого раунда выполняется расчёт последнего завершённого раунда. Если идёт финальный раунд, вызываем ResetCircuitInfo, чтобы обновить данные игрока. Мы знаем, из скольких раундов состоит игра благодаря редактируемому свойству в устройстве Verse, в котором задаётся общее количество раундов для игры. Авторы островов должны убедиться, что это свойство соответствует настройкам раундов.
Слабый ассоциативный массив сеанса и слабый ассоциативный массив игрока
Новый шаблон «Создание гоночной трассы» — прекрасная возможность показать разницу между двумя слабыми ассоциативными массивами и объяснить, когда нужно использовать тот или иной тип в коде.- Слабые ассоциативные массивы сеанса пригодятся для паттернов типа «одиночка» и хранения данных для текущего раунда, если вы не хотите совершать повторные вычисления.
- Слабые ассоциативные массивы игрока предназначены для показателей, которые должны сохраняться между множеством раундов и сеансов, но при этом должны быть связаны с отдельными игроками.
Триггер импульса и Sequencer
В оригинальной версии шаблона чтобы запустить сигнал к началу гонки — «на старт, внимание, марш!», — мы использовали устройство «Триггер импульса». Оно активировало триггеры для отображения текста и запуска огней для стартовой линии и тем самым воспроизводило последовательность событий в течение определённого времени.В обновлённом шаблоне мы решили вставить видеоролик начала гонок и заменили изначальное устройство на Sequencer. Благодаря этому инструменту нам удалось добавить в сцену разные камеры, элементы интерфейса и динамический вид сверху, который подстраивается под количество активных игроков.
Как и в случае с триггером импульса, мы подключили устройства к последовательности в важные моменты и знаем, когда нужно отображать счёт следующего игрока, а когда — пропускать видеоролик.
Что дальше?
UEFN не стоит на месте, и мы вполне уверены, что и этот шаблон будут ждать изменения в будущем. Наша цель — сделать всё, чтобы вы могли строить сложные, нестандартные, но при этом интересные острова с помощью новых функций и инструментов.Нам не терпится увидеть, как нововведения могут изменить этот шаблон. А пока скачивайте шаблон, знакомьтесь с его тонкостями и переносите технический функционал в свои проекты. Найти его в UEFN можно на вкладке шаблонов. Будем рады видеть ваши трассы, списки лидеров и другие интересные детали!