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

Когда я работал над Starhawk, у нас была критическая функция в игре, которая позволяла развертывать «исправления» для обновлений данных (как правило, корректировки игры / баланса) без необходимости в крупном патче, который пройти недельный (как минимум) патч и процесс контроля качества Sony. Это был мой первый опыт работы с обновлениями игры, для которых не требовалось полноценное двоичное обновление.

Вскоре после этого я пару лет работал над мобильными играми, и, как я уверен, многие знают, что любая возможность обойти процесс проверки в iOS App Store - прекрасная - ну, необходимая вещь. Итак, для нашей команды мы обрабатывали все игровые данные с помощью обширного объема данных JSON для определений уровней, профилей игроков, настроек, данных игры и балансировки, запуска специальных событий и сделок и т. Д. И т. Д. . Я верю, что мы также хранили данные игроков на защищенном сервере / базе данных в виде данных JSON, но это не было и по-прежнему не в моей сфере. К счастью.

Цели для игровых данных и Live-Ops

Мне нравится хранить как можно больше игровых данных в текстовых файлах данных (особенно в файлах JSON). И когда я говорю об игровых данных, я имею в виду такие вещи, как механические данные (которые в основном представляют собой просто список ссылок на другие файлы данных и пути к игровым ресурсам), шаблоны механических частей, которые используются для процедурной генерации внутриигровых предметов, игры параметры мира, профили и настройки игроков и так далее. Эти же форматы также используются для хранения данных, созданных в игре; хотя элемент может быть сгенерирован из одного или нескольких шаблонов данных, в конечном итоге он должен быть где-то сохранен и сохранен. Эти файлы практически не трогаются, кроме сохранения / загрузки.

Тем не менее, эти файлы также сохраняют ссылки на свои исходные шаблоны, а это означает, что если какой-либо шаблон окажется слишком мощным, исходный шаблон можно настроить, и последствия этого будут отражаться на всем, что было создано в игре.

Поскольку это все основные текстовые файлы, к которым я могу получить доступ, я могу легко настроить их и просто обновить в игре. Возможность легко изменять игровые данные в редакторе и извлекать их с помощью простого обновления, но это также было основой разработки и дизайна игр на протяжении веков (так называемый геймплей / контент на основе данных). Unreal Engine 4 позволяет выполнить весь этот рабочий процесс, но в какой-то момент игровой контент должен быть упакован, и, насколько мне известно, помимо этого, он содержится в бинарных пакетах. И что мне нравится в моих игровых данных, так это то, что их всегда легко получить, настроить, загрузить и т. Д. В процессе разработки, независимо от того, свободная это сборка или пакетная сборка. Что-то, к чему я также привык после нескольких лет в мобильных играх, - это отсутствие необходимости полагаться на полное двоичное обновление / патч для игры, чтобы вносить изменения, особенно если все это представляет собой немного больше, чем проход настройки или исправление небинарного патча. Я бы предпочел, чтобы игроки просто загрузили игру, имели период обновления в десять-двадцать секунд и просто имели все обновленные настройки. Весь этот процесс также лежит в основе любой настройки «live ops» после запуска, с которой я работал: обновляйте некоторые файлы на авторитетном CDN, игроки загружают их при выходе в Интернет, и теперь у вас есть 24-часовое специальное мероприятие с уникальными Предметы.

И когда я начинаю эту статью, я очень надеюсь, что первый комментарий где-то не «подожди, ты не просто использовал ‹x›?», Раскрывающий критический и полностью соответствующий набор функций. это было бы невероятно полезно. Но я не думаю, что дело обстоит именно так в будущем.

Удивительное осознание

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

Написав это, я понял, что должен отметить: это было очень в начале моего времени с UE4 (и я никогда не использовал предыдущую версию Unreal Engine).

Во всяком случае, да, так что: нет. Чертежи вообще не работают; на самом деле, все наоборот: при создании контента проекта чертежи фактически встраиваются в код C ++ - потенциально самая нижняя ступенька лестницы легко обновляемых игровых данных. Итак, все действительно пошло в другом направлении, чем я ожидал.

После Blueprintpocalypse 2017 прошло довольно много времени, и мне пришлось просто потратить на создание самой базовой кодовой базы, необходимой для начала серьезной работы над самой игрой. А затем устанавливаем основы критических участников / компонентов / и т. Д. Игры. И именно после этого начального этапа разработки я начал искать необработанный (сырой. Получить его. Потому что ... ну ... контент готовится? Тише.) Способ поддерживать данные игры, конфигурации, локальные профили и другие подобные вещи, которые не были 't не требуется использовать кулинарию во время выполнения игры.

Несмотря на мое желание просто перейти к JSON для игровых данных, я хотел увидеть, каковы стандартные / рекомендуемые практики для UE4 при проектировании и разработке на основе данных. Я склонялся к использованию таблиц данных, поскольку они описаны в документации, буквально озаглавленной Элементы игрового процесса, управляемые данными. И это звучало, ну, это было связано с Excel, так что это не звучало великолепно, но это было что-то. Затем я изучил это и обнаружил, что вы можете манипулировать данными извне, но в конечном итоге их нужно будет импортировать в UE4 для использования. При необходимости вы можете экспортировать его позже, но в конечном итоге его придется импортировать повторно. И в итоге приготовили.

Так что да. Уииеее.

Нажмите X, чтобы получить JSON!

да. Хотя бы раз в день, когда я внутренне думаю о JSON, я мгновенно слышу JASON! ДЖААААСОН! ДЖЕЙСОН! в моей голове. В любом случае, да, мне нравилось работать с файлами JSON либо из-за их простоты, либо из-за привычки, поэтому я затем решил выяснить, как заставить это работать. К счастью, я обнаружил, что в UE4 есть модули Json и JsonUtilities!

Итак, я проверил документацию после беглого просмотра исходных файлов. А документация для Json и JsonUtilities была ... Хорошо. Это было то, что вы видите. И в случае, если кто-то прочитает это через год или что-то в этом роде, и это изменится, для потомков позвольте мне сообщить вам: здесь не на что смотреть.

Тем не менее, исходник было несложно осмыслить. Однако применение его на практике было другим делом. Моим первым тестом функциональности модулей была сериализация экземпляра моего механического актора. И мне удалось заставить его работать довольно быстро и легко! И если вы ожидаете, что за этим заявлением последует «но…»……… Да, есть «но»:

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

После небольшого рытья - и довольно обширного количества проб и ошибок - я в конце концов дошел до того момента, когда, пока я придерживался структур, состоящих исключительно из довольно простых типов данных, я мог использовать утилиты сериализации UE4, чтобы легко сериализовать и десериализовать данные структуры.

Однако использовать эту структуру данных в мельчайших деталях остального игрового кода не так просто. C ++ с UE4 не является полностью стандартным C ++. Структура, распознаваемая Unreal Header Tool (и Unreal Build Tool), должна обозначаться макросом USTRUCT. И, в отличие от стандартного C ++, USTRUCT struct не «в основном» то же самое, что класс. Он предназначен (и строго соблюдается) как структура базовых данных, которой не нужно тщательно управлять сборщиком мусора движка. Я немного не понимаю в деталях, так как я не работал над этим какое-то время, а также работа над всеми областями игры имеет тенденцию затемнять специфику работы, проделанной неделю или две назад; месяц назад - это просто путь слишком далеко назад, чтобы даже думать о нем.

Короче говоря: чтобы действительно иметь возможность просто использовать данные, сериализованные / десериализованные с помощью USTRUCT, я решил, по сути, создать почти точную копию UCLASS (с некоторыми преобразованиями / настройками, происходящими во время передачи в некоторых случаях). И как только этот UCLASS будет заполнен восхитительными данными, его можно будет использовать повсюду по назначению.

Я подбросил суть (также видно ниже) старой версии моей структуры данных механической части самого высокого уровня, которая существует в моей кодовой базе (по мере того, как вы спускаетесь вниз по дереву, она быстро становится больше плотный). В этом смысле также используются мои любимые, хотя и совершенно уродливые наборы макросов, которые я когда-либо создавал: генераторы макросов-аксессоров. Это не что иное, как ярлык для создания базовых методов доступа get / set в UCLASS версии структуры данных (то есть не полностью в отличие от свойств C #), но это был удобный способ урезать определение. и устраните как можно больше места для ошибок при реализации. Эта высокоуровневая структура данных части служит, по сути, прапрадедушкой для более конкретной логики части, но каждый дочерний элемент отвечает только за управление своими собственными данными; любой родитель этого ребенка будет заботиться о своих данных, а родитель этого родителя позаботится о своих данных и так далее.

В любом случае, да, вот в чем суть - на самом базовом уровне - того, как я закончил работу над дизайном / разработкой на основе текстовых данных. Возможно (и я действительно надеюсь, что это не так) лучшее или самое элегантное решение, но оно выполняет то, что я хочу: внешние файлы данных, которые не требуют кулинарии, которые используются в игре; тем не менее, вы должны убедиться, что все файлы данных, необходимые для готового игрового проекта, включены в итоговые сборки проекта. Если вы просто не хотите хранить все на сервере и загружать его при запуске, что я тоже могу сделать, но я не хочу заставлять начинающих игроков выходить в онлайн, чтобы хотя бы войти в игру, так что « стартовый набор »данных входит в состав сборок.

Кроме того, я не могу полностью выбросить свой модуль сериализации JSON, но я включил очень, очень простую (но очень полезную) оболочку для основных операций: JoySerializationManager.h и JoySerializationManager.cpp.

ПРИМЕЧАНИЕ. Я не обращаю внимания на всю сложность, которая существует как часть всей этой системы и настройки; частично потому, что это не самая сексуальная тема, о которой можно писать, и я не знаю, увидит ли кто-нибудь когда-нибудь эту заметку. Но еще и потому, что это было действительно раздражающим и отнимающим много времени, поэтому я не уверен на 100%, что решение, которое у меня есть, является правильным. Я не люблю торговать ложью. Хорошо. На данный момент в этом контексте.

Дополнительные функции и будущая работа

Функции простоты использования («Качество жизни»)

Обычно я всегда держу всю свою библиотеку файлов JSON открытой в VS Code, поскольку это, безусловно, мой любимый редактор для работы, которая не выполняется на C / C ++ / C #. Если мне нужно изменить настройки игры или настроить балансировку механического оружия или его ног (иногда я настраиваю ноги), я просто нажимаю Alt + Tab в код VS, делаю изменения и возвращаюсь к работе.

То, что было сразу очевидно, добавить в мою кодовую базу после дня или двух, - это возможность редактора просматривать (определенные каталоги) файлов JSON и, при изменении, автоматически перезагружать файл.

И я говорю определенные каталоги, поскольку есть некоторые изменения в файлах, которые я не хочу просто перезагружать волей-неволей. Если я нахожусь в сеансе, внесите изменения в снаряжение меха, я не хочу, чтобы снова вставлялись alt + tab и у меня отнимали ноги, потому что я написал что-то не так, а затем вылетает, и тогда я, вероятно, буду много плакать . Итак: большинство каталогов. Однако возможность перезагрузки меховой загрузки в середине сеанса удобна, поэтому я добавил консольную команду, чтобы обновить текущий файл конфигурации или полностью загрузить другую конфигурацию. Механизм полностью воссоздан в коде, но из-за избытка итераций и раздражения я не знаю, создавал ли я когда-либо в своей жизни более изящный класс, работающий с ошибками и восстановлением. Механический код - это просто машина. да. Пун'д.

Серверы и безопасность

Как я уже упоминал, абсолютно необходимо иметь возможность отправлять / получать данные JSON на / с сервера; возможность обновлять файлы данных на стороне сервера, а затем полагаться на игровой клиент для запроса и получения обновлений при запуске / подключении к сети - в конце концов, вся цель усилий.

Это вопрос безопасности для этих файлов, который, по общему признанию, не является областью, в которой я являюсь экспертом или даже новичком, а является парочкой «членов команды» Joy Machine (нет денег, чтобы никому платить, и поэтому никто активно работает - сохраните моего главного операционного директора и финансового директора, но у них есть дополнительные льготы - но они все еще помогают планировать / проводить мозговой штурм / они прекрасны), начали исследовать несколько возможностей. Я напишу об этом, когда мне об этом расскажут. Может быть. Это может быть зашифрованная статья.

Конец игры

Моя мечта о мечтах, помимо оперативных работ, исправлений и прочего, состоит в том, чтобы управлять «библиотекой активов» игры с помощью простых обновлений файлов JSON. И нет, я не имею в виду волшебным образом переносить меши, текстуры, карты и так далее и тому подобное. Это было бы глупо. Я имею в виду, что я могу поддерживать библиотеку активов идентификаторов активов («короткие имена») для сеток, текстур и т. Д., И этот идентификатор сопоставляется с путем к активу, который представляет короткое имя (так что это больше похоже на реестр). Записи библиотеки активов могут быть добавлены и удалены и все такое, но они также могут - при желании - обновить актив, на который ссылается короткое имя, в случае, если один актив удален, но короткое имя все еще применимо к чему-то, что принимает его место. Ничего из этого не потребует изменений где-либо еще, это просто сработает.

И также стоит отметить: это здорово на практике, но также важно не делать глупостей и навсегда оставить библиотеку ресурсов с кучей ссылок на один существующий актив. Идея состоит в том, что для любого фактического обновления / исправления библиотека очищается, перестраивается и перераспределяется - и как часть этого процесса сборки она обновляет любой файл данных, который по мере необходимости использует идентификатор, который скоро будет устаревшим. И нет, восстановление - это не самый быстрый процесс в мире, но он не выполняется вручную, поэтому мне это нравится.

Опять же: мечта о мечтах, но я действительно с нетерпением жду возможности увидеть, смогу ли я в конечном итоге легко добавить полностью «новый контент» в игру с добавлением пары новых конфигураций частей, состоящих исключительно из уже существующих ресурсов, но собранных с использованием другого набора правил (данный Часть строится из подмножества сеток / материалов, чтобы сформировать фактическую «часть») для различных целей, при этом пользователи даже не осознают, что произошло изменение. Хотя мне не нравится идея невидимых изменений, поэтому я бы включил постоянный «журнал изменений» на видном месте в потоке пользовательского интерфейса, чтобы игроки могли его просмотреть, если они того пожелают.

В заключение

Как я сказал в начале, я и надеюсь, и не надеюсь, что кто-то сразу скажет: «ЭЙ, ВЫ НЕ ЗНАЛИ О ‹X›?» и разрушает мою ночь, но, тем не менее, системы на месте в настоящий момент уже работают замечательно, так что я не могу слишком сильно жаловаться. И, в отличие от Blueprintpocalypse, вероятность того, что изменение кода приведет к сбою файла JSON при открытии VS Code,… мала.

Но все это делается для того, чтобы становиться все ближе и ближе к целям для систем, которые я хочу использовать как для Steel Hunters, так и для будущих проектов; Я постоянно оцениваю рабочий процесс, эффективность и удобство использования ВСЕ ВЕЩИ (а также делаю все возможное, чтобы уменьшить количество человеческих ошибок при работе с большим объемом данных в определенный момент времени или очень, очень долгая ночь), и этот менталитет на самом деле уже дает некоторые действительно отличные вещи. Даже если это иногда означает еще один рефакторинг чего-то. Это случается не так часто, как я, наверное, сказал. Не так часто. Это случается. И: плачет.

В любом случае, вот скриншот одного из серии высокоуровневых «зарисовок» макета, которые я сделал неделю или две назад: