Gallllery | Образование, издания и коллекции по современному искусству
Исходный размер 1141x1601

В прошлых главах мы рассмотрели, как создавать сами системы, однако работа на этом не заканчивается, ведь любая система затем используется для реализации игрового контента всех возможных типов. При это заниматься этим, по большей части, будут не сами разработчики, а другие специалисты, участвующие в проекте (что мы уже поверхностно затронули в блоке про Доступность).

Таким образом, ответственность разработчика — не только создать систему, но и организовать структуры взаимодействия с ней. В этой главе мы рассмотрим следующие аспекты подготовки системы к использованию:

— Заполнение системы данными — Настройка систем на уровне — Удобство тестирования изменений — Расширение функционала взаимодействия с движком — Визуальные оболочки

Заполнение системы данными

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

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

UE предлагает различные системы хранения данных, и далее мы рассмотрим, в каком случае стоит применять ту или иную структуру. Нами будут рассмотрены:

— DataTables — DataAssets

А также мы поговорим про Structures и Enumerations, как об инструментах для организации хранения данных.

Структуры хранения данных

Основные структуры хранения данных (не считая переменных внутри отдельного актера или системы) — это DataTables (в дальнейшем Таблицы) и DataAssets (в дальнейшем Конфиги).

DataTable — как и следует из названия, это таблица, по своей структуре идентичная тем, что мы используем в офисных приложениях (за тем исключением, что DT не поддерживают формулы и прочие операции, и являются лишь инструментом хранения данных в формате таблицы).

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

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

Исходный размер 1918x891

Пример DataTable c параметрами для разных типов Юнитов

Однако, главный минус Таблиц — необходимость написания системы обращения к ней внутри актера, которому нужны хранимые параметры.

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

DataAsset — это Шаблон, из которого можно создавать отдельные ассеты, хранящие определенный набор параметров.

Главным плюсом Конфигов является возможность легко указывать актеру, какой именно конфиг ему необходимо использовать, поскольку DA можно легко указать как переменную внутри актера.

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

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

Исходный размер 1117x281

Пример набора DataAssets с данными для массовки на локациях

Типы хранимых данных

В прошлом блоке мы рассмотрели системы хранения, однако, чтобы разобраться, в каких случаях их применять, необходимо проанализировать типы хранимых данных, и сопоставив их требования с плюсами и минусами той или иной системы, сделать выводы. Я выделяю следующие виды хранимых параметров:

— Параметры, используемые в конкретной системе

Это параметры отдельной игровой сущности. Например, аспекты поведения камеры игрока, параметры передвижения игрового персонажа и т. д.

Главным аспектом здесь является факт, что это данные предназначенные для отдельной сущности и существующие, по сути, в единственном экземпляре.

Для подобных параметров лучше всего подходят именно DataAssets,

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

Исходный размер 959x528

Пример неправильной реализации хранения параметров персонажа игрока в рамках DataTable.

— Параметры, используемые в наборе сущностей одного типа

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

Например, набор настроек игрового уровня, или параметры, которые использует каждый NPC в игре.

Для подобных параметров релевантной системой хранения может быть как DataAsset, так и DataTable, в зависимости от того, нужно ли разработчикам сопоставлять параметры разных сущностей между собой или нет.

Рассмотрим, для примера, ту же систему способностей персонажа, которую мы затрагивали в блоках про разработку систем. Предположим, нам нужно хранить информацию о том, какие персонажи имеют какие способности.

Если набор способностей каждого персонажа в понимании гейм-дизайнера атомарен, и не подразумевает его сравнения со способностями других персонажей — удобно поместить этот список в Конфиг.

Это, к тому же, позволит давать разным персонажам один набор способностей, просто указав ему тот же конфиг, без необходимости настраивать каждого отдельно.

Однако, если в игре важен баланс между способностями всех персонажей, то гораздо логичнее организовать их в формате таблицы,

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

Виды переменных для хранения данных

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

— Structures

Структуры — набор переменных, объединённых в одну, что позволяет вам группировать данные по типам. Крайне важный тип переменной в рамках систем хранения, поскольку, например, DataTable строится именно на основе одной структуры, из переменной которой и появляются столбцы таблицы.

Однако у структур есть еще одна очень важная роль:

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

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

Однако, с вложением функций нужно быть осторожным, поскольку чем больше уровней внутри системы одной структуры — тем сложнее получать из нее конкретную переменную, а уж тем более менять ее в процессе игрового процесса.

Исходный размер 1231x549

Пример структуры с несколькими уровнями вложения

— Enumerations

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

Главное преимущество энумерации — возможность делать понятный список выбора тех или иных опций.

Предположим, у нас есть универсальная функция: создать заклинание. Нам необходимо каким-то образом указывать, какое именно заклинание необходимо создать. Без энумераций мы могли бы пойти двумя путями:

— создать систему индексов, однако в таком случае необходимо где-то хранить список соотнесений индексов и заклинаний.

— вводить название заклинания, что, с одной стороны, позволяет нам легко понимать, что за заклинание мы вызываем, но с другой делает критичным аспект неправильного написания названия.

Исходный размер 1227x462

А использование Enumeration позволяет нам просто и удобно выбрать нужную нам опцию из визуально понятного выпадающего списка.

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

Удобство тестирования изменений

Короткий, тем не менее очень важный блок, неправильная реализация которого может сильно усложнить настройку и тестирование вашего проекта.

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

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

Представим, что у нас есть проект, в котором имеется система сценариев. В этой системе сценариев хранятся все основные параметры миссии: количество противников, их типы, частота появления волн врагов и т. д.

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

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

Настройка систем на уровне

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

Переменные, доступные на уровне

Они же, InstanceEditable переменные. Одна из первых вещей, с которыми знакомятся начинающие разработчики до того, как разберутся в прочих способах получения референсов на других актеров в UE.

Однако основная их роль — возможность настраивать отдельного актера непосредственно на карте. В своей сути это очень простая система, поэтому мы не будем заострять на ней внимание, однако хочется отметить один аспект:

При создании InstanceEditable переменных очень важно присваивать им правильные категории.

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

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

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

До и после добавления категорий к переменным

Также, все категории в панели Details расположены в алфавитном порядке.

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

Функции, доступные на уровне

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

Например, вы можете создать действие, которое повернет вашего актера ровно на 90 градусов, или покажет дебаг радиуса влияния сущности, или проверить доступность актера в рамках навигационной системы…

Исходный размер 1913x898

Пример множества InEditor. Функция для разработки и тестирования системы разбиения объектов на карте на группы. Автор системы — Амир Абу Махади.

Однако, стоит отметить, что подобные функции имеет смысл использовать только если это действие относится к конкретному актеру. Если вам необходимо создать универсальное действие, которое можно вызвать у актёров различных типов — рациональнее не дублировать код функции, а применить EditorUtility, про которые мы поговорим в следующем блоке.

Расширение функционала взаимодействия с движком

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

Большинство подобных улучшений создаются при помощи создания EditorUtilityAction или EditorUtilityWidget.

Где Action — это определенный скрипт, который можно запустить на ассете или актере определённого типа для совершения каких-либо действий, а Widget — отдельное окно, открываемое в рамках интерфейса UE со своими переменными, кнопками и т. д.

Давайте рассмотрим одну конкретную систему, и как автоматизация позволяет упростить работу с ней.

В одном из наших проектов для реализации Анимаций сущностей использовалась технология вертексных анимаций (когда анимация реализуется не с помощью скелета, а с помощью анимированного материала, который двигает вертексы модели для создания движения).

UE имеет встроенные плагины для создания подобных анимаций, однако не существует отдельного удобного инструмента для взаимодействия с этой системой. А с учетом того, что на каждую модель необходимо иметь по 20-30 анимаций, создание их вручную заняло бы очень много времени у команды.

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

Loading...

Результат: EditorWidget может сделать процесс понятным и простым, благодаря визуальным кнопкам для реализации каждого действия.

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

В итоге было принято решение написать скрипт в рамках EditorUtilityAction. В рамках него все анимации сортировались в определённую структуру папок, а затем, при вызове действия, скрипт брал из этой структуры все нужные анимации и правильно интегрировал их в DataAsset нужного персонажа.

Исходный размер 1025x814

Пример: Результат сортировки алгоритма всех анимация для одного типа юнитов

Результат: EditorAction может помочь автоматизировать часть работы, при этом исключая возможность ошибки человека из-за слишком большого количества контента при работе.

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

Но имея на руках уже написанные системы, можно также автоматизировать и процесс их связи между собой. В итоге, когда потребовались изменить большую часть анимаций, инструмент их создания был переработан так, чтобы он сам проходился по всем персонажам, создавал все нужные для них анимации, а затем сортировал всё готовое по системе папок, необходимой для создания конфигов.

До и После автоматизации инструмента для создания вертексных анимаций

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

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

Визуальные оболочки

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

По сути именно этому и был посвящен весь блок про создание системы взаимосвязей в рамках набора сложных систем. Любой проект содержит множество логических систем. Часть из них уже имеют удобные инструменты для визуальной настройки в рамках UE (например, BehaviorTree для логики поведения врагов или AnimGraph для создания структуры анимаций персонажа), однако многое остается неохваченным ввиду уникальности этих систем для различных проектов (например, структура развития квеста, структура диалога и тд.)

Важность визуальной оболочки для структур логики можно рассмотреть на простом примере: UE не имеет системы дерева анимаций для 2D проектов.

В итоге, в 3D мы имеем возможность легко помещать анимации в граф и настраивать условия перехода между ними, а в рамках 2D проектов вынуждены прописывать логику в рамках стандартных блюпринтов, делая цепочки проверок условий, что сильно усложняет процесс и снижает визуальность. (Однако радует, что эта проблема была, наконец, решена с помощью плагина PaperZD).

Разработка визуальной оболочки — сложный процесс, который требует хорошего знания структуры UE, однако если ваш проект подразумевает сложные структуры логики (например — квестов), реализация такой системы может сильно упростить всю дальнейшую работу команды.

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

Работа с системами
Проект создан 29.03.2024
Глава:
1
2
3
4
5
Загрузка...
Мы используем файлы cookies для улучшения работы сайта и большего удобства его использования. Более подробную информац...
Показать больше