ЛЕТО 2024 ТЕХНИЧЕСКОЕ ОБЪЯСНЕНИЕ: Система компонентов сущностей Hytale

Привет всем! Сегодня мы собираемся заглянуть за занавес некоторых технологий, лежащих в основе движка Hytale, с особым акцентом на одном из фреймворков, который мы недавно анонсировали: Flecs — легкой и мощной системе компонентов сущностей (ECS).

Некоторое время назад мы рассказывали о нашем решении перезагрузить движок Hytale, перейдя от сервера на Java и клиента на C# к созданию обоих на C++. Причин для этого было много: мы хотели обеспечить возможность выпуска игры на нескольких платформах, повысить производительность при работе с устройствами с более низким разрешением, а также создать достаточно надежный движок, чтобы иметь возможность патчить и поддерживать игру в будущем.

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

Но прежде чем мы слишком глубоко погрузимся в сам Flecs, нам нужно взглянуть на ECS — паттерн системы компонентов сущностей.

От одной трехбуквенной аббревиатуры к другой

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

Большая часть традиционной разработки игр опирается на устаревшую модель объектно-ориентированного программирования (ООП) или на архитектуры "сущность-компонент" (или "актер-компонент"!). Объектно-ориентированное программирование преобладает в разработке программного обеспечения в целом и разбивает проблемы на знакомые структуры, которые можно рассматривать как объекты. У вас может быть общий тип объекта Character, который обеспечивает игровую логику, общую для всех персонажей, которая затем наследуется или специализируется объектом Player, различными объектами NPC и любыми другими типами, которые могут считаться персонажами.

Это дерево может стать очень широким.

Парадигма "сущность-компонент" еще на шаг приближает нас к ECS и является основной архитектурой, используемой во многих популярных игровых движках, таких как Unreal и Unity. В этой парадигме у нас есть сущности — отдельные единицы, такие как "игрок", "NPC", "стул" — и компоненты — комбинация данных и функциональности, которые могут быть прикреплены к этим сущностям. Каждая сущность состоит из нескольких компонентов. Если вы знакомы с ООП, то парадигма "сущность-компонент" в значительной степени опирается на принцип "композиция вместо наследования". Например: игрок может иметь позицию в мире, возможность считывать входные данные контроллера и инвентарь; NPC также имеет позицию, может иметь инвентарь и обладает некоторой формой поведенческой логики; наш стул, к сожалению, имеет только позицию.

Пока вы не добавите к нему поведенческую логику, и он не станет существом [отказ от ответственности: это сделано в демонстрационных целях!]

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

Сущность может быть составлена разными способами!

Но это все еще не ECS. ECS — система "сущность-компонент" — берет эти концепции и продвигает их дальше. Если в модели "сущность-компонент" функциональность (например, методы и функции) находится внутри самого компонента, то в ECS эта функциональность отделена от данных и состояния, которые она обрабатывает. Вместо того чтобы иметь каждый компонент со своей внутренней логикой обновления, мы имеем системы, которые сопоставляют сущности с определенными наборами компонентов и действуют на их основе. Это означает, что в ECS мы сохраняем возможность компоновать сущности из разных компонентов, но разделение приводит к созданию архитектуры данных и логики, которая значительно более эффективна для аппаратного обеспечения и, следовательно, более производительна. Многие детали того, как ECS достигает этих преимуществ в производительности, являются сугубо техническими, но достаточно сказать, что это включает в себя использование преимуществ архитектуры процессора, структурирование данных плотным образом, чтобы извлечь выгоду из их локальности в шаблонах доступа, и использование этих шаблонов доступа для распараллеливания как можно большего количества логики, насколько это возможно.

Системы могут сочетать в себе любые компоненты.

ECS в устаревшем движке

Мы знали, что хотим перейти на архитектуру ECS еще во время разработки устаревшего движка, поскольку она обеспечит нам прирост производительности и масштабируемости, а также естественное соответствие нашему подходу к построению и настройке игровых объектов и актеров, основанному на данных. В результате мы разработали собственную Java-реализацию этой концепции и начали интегрировать ее в унаследованный сервер. На тот момент у нас не было аналога для клиента на C#, поэтому наша реализация была исключительно серверной.

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

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

Надежная основа для нового движка

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

Оценив все возможные варианты, мы остановились на Flecs — высокотехнологичном фреймворке ECS, написанном и поддерживаемом экспертом по ECS Сандером Мертенсом.

Уже из коробки он предоставляет нам доступ к множеству функций, характерных для большинства реализаций ECS, а также отличную производительность и многоплатформенную совместимость. Благодаря тому, что он полностью написан на языке C с API на C++, он работает значительно быстрее, чем любая реализация на C# или Java, позволяя нам в полной мере использовать преимущества интеллектуальной реализации распараллеливания и многопоточности. Еще одним очевидным преимуществом является то, что нам не нужно самим заниматься его поддержкой — Flecs проверен в боях, получает частые обновления и исправления ошибок, а благодаря обширному набору тестов мы можем быть уверены в его стабильности.

Но, пожалуй, самым привлекательным аспектом стал широкий набор функций, выходящих за рамки традиционного фреймворка ECS и обеспечивающих гибкость, которая выводит ECS на новый уровень. Одним из примеров этого является концепция "отношений". Как и компоненты, отношения — это данные, которые вы можете прикрепить к сущности, но эти данные используются для связи одной сущности с другой. Хорошим примером являются отношения "родитель-ребенок", когда сущность игрока может иметь в качестве дочерней сущность камеры, которая следует за ним по пятам. Другой пример может быть еще более буквальным: сущность A любит сущность B. Используя эту структуру, мы можем легко выполнять такие запросы, как "найдите мне все сущности, которым нравится сущность B" или "найдите мне все сущности, которым нравится сущность B".

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

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

Более быстрое мышление

В заключение мы рассмотрим один из таких примеров. В прошлом мы представили улучшение для NPC Hytale под названием Combat Action Evaluator. Это фреймворк, разработанный для того, чтобы позволить NPC принимать более "умные" и "нечеткие" решения о том, какую атаку использовать и на какую цель, основываясь на ряде настраиваемых параметров. Несмотря на то, что изначально он был реализован в унаследованном движке, с самого начала он был задуман как управляемый данными, с каждым отдельным входом, прикрепленным подобно компонентам в ECS.

Хотя в устаревшем движке он прекрасно справлялся со своей задачей и обеспечивал боевых NPC, которых порой можно было принять за людей, пришлось наложить на него ограничения из-за его потенциального влияния на общую производительность игры. В конце концов, если позволить NPC принимать "нечеткие" решения на основе огромного количества входных данных в среде ООП, это означает значительную нагрузку на обработку данных, с которой наш движок на базе Java, предшествовавший созданию ECS, не справлялся. Поэтому мы запускали оценщик боевых действий только через нерегулярные промежутки времени. Это могло бы означать, что мы избежим потенциального замедления работы сервера из-за большого количества NPC, ведущих активный бой, но это также означало, что они будут принимать решения медленнее — достаточно медленно, чтобы быть заметными для игрока.

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

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

К будущему

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

1141 просмотров
2 комментария
Пожалуйста, создайте учетную запись или
авторизуйтесь прежде чем оставлять комментарии