Прежде чем рассказать про архитектуры игровых движков, я подумал, что будет полезно немного рассказать о том, как я понимаю архитектуру ПО и как это связано с играми. Во-первых они (архитектуры) есть, чтобы бы там не врали про игрострой. Во-вторых их оказывается больше одной. Это, возможно, поможет вам понять почему остальные статьи написаны в таком порядке, или без какого-то порядка. В худшем случае, когда вас втянут в спор о том, насколько отвратительны (или, наоборот, потрясающе гениальны) отдельные игровые движки и их архитектуры, у вас будет пара аргументов и понимание что к чему.
Символично, что статья про архитектуру игрового движка появилась после того, как было расказано про строки, мультипоток, применение алгоритмов: просто оно так и в жизни получается, мы сначала пишем код, редактор, игру – костяк проекта обрастает мясом, и тут нас догоняют проблемы, на которые все забивали, потому что надо было выдать хоть что-то похожее на работающий вариант. Но от того, что мы забивали на проблемы и заметали их под коврик беклога, проблемами быть они не перестали.
Вы не получите из статьи знаний об аллокаторах, контейнерах, или математике, стоящей за физикой игры. Так-же я не ставлю целью, научить вас, как применять A* разбиение в поиске пути неписей или моделировать реверберацию комнаты. Вместо этого есть размышления о коде между всем этим. И даже не столько про написание кода, сколько о его организации.
Game++. Dancing with allocators
Game++. Juggling STL algoritms
Game++. Building arcs <=== Вы тут
Каждая программа имеет свою архитектуру, «запихнул все в main() и как то работает» тоже своего рода архитектура, поэтому, думаю будет более интересным поговорить о том, что делает игровой движок хорошим.
Никто не пишет игровой движок просто так, он рождается либо в процессе создания игры, как необходимость формализовать, обезопасить и сохранить отдельные части игры для дальнейшего применения. В таком случае появляется редактор, система сборки ресурсов, отдельный ввод-вывод, выделяется в отдельную систему рендер и многое другое – и у вас сама собой появляется группа ответсвенных людей для поддержки редактора и движка. Обычно это происходит после выпуска игры и понимания, что так дальше жить нельзя и не получится.
Второй вариант сама игра и есть и редактор, и движок и билд система, которая сможет собрать себя же в качестве готовых уровней и логики. Все игровые движки и редакторы появились из игр, какие-то игры (и затем движки-редакторы) стали успешными и команды, подумали на волне успеха получить дополнительное время для развития.
К этому времени обычно в команде появляется (вырастает, реже – приглашают) человек, который определяет, уточняет, управляет и контролирует компоненты внутри игры-движка, обеспечивая их взаимодействие и целостность в рамках всей системы. Можно называть его Архитектором, но чаще – это Старейшина прогерской части студии, которому больше вех перепало работать c QA, прогерами, дизайнерами и другими людьми.
Каждый рабочий день, последний десяток лет я смотрю в код игр, разных игр, и разных движков, в основном крупных и достаточно взрослых в плане времени разработки. Конечно, как и у любого программиста занятого долгое время в определенной области, у меня есть понимание хорошего дизайна. И я думаю все переживали моменты, когда увиденный код был настолько плох, что лучшее, что можно было с ним сделать — это упокоить его в коментах и рядом написать всё заново. Лучшее, однако не значит, одобренное начальством – старый и ужасный легаси код обычно относительно хорошо протестирован и известны места расположения граблей, а вот с новым вам еще предстоит их обнаружить.
Немногим из нас повезло работать с идеально спроектированным кодом. Тот самый код, проект или движок, который ощущается как роскошный американский седан из 70-х, у которого всё есть, надо только знать где лежит, готовый набрать сотню легким касанием тапки в пол. И вот, работая с разными кодовыми базами я стал замечать, что игровые движки похожи на команды, которые их пишут. Когда команда становится больше пяти человек они начинают организовывать свою работу, и часто это приводит к разделению задач и обязанностей на основе технических возможностей каждого участника команды. Каждый делает то, что умеет и знает: внутренюю БД, рендер, физику, редактор, тесты и т.д. Такое разделение выглядит вполне логичным с точки зрения организации — каждый человек на своем месте, что помогает снизить нагрузку и повысить эффективность. Вроде бы, но есть и другой эффект, разделение приводит к тому, что разные части системы не могут эффективно взаимодействовать, и разработка становится затрудненной, потому что специалисты работают в изолированных подсистема, не общаясь между собой по важным вопросам. Это искусственное разделение в итоге затруднияет обмен знаниями и приводит к слабой интеграции между компонентами игрового движка.
Эту закономерность между структурой движка и внутренней организацией команды, подметил еще в 60-х годах прошлого века Мелвин Конвей. Закон Конвея, который Мелвин Конвей сформулировал в конце 1960-х годов, утверждает, что структуры организации, участвующие в проектировании систем, в конечном итоге влияют на архитектуру этих систем. Проще говоря, организациям сложно создавать системы, которые были бы структурно или функционально независимы от того, как эти организации организуют свои коммуникации. Причем это оносится не только к игровым движкам, это будет относиться к любому софту, который делает команда. Когда программисты или архитекторы проектируют систему, они несознательно воспроизводят в структуре кода те же разделения, которые существуют в самой организации. Если команда разработки разделена на несколько частей — одна работает над фронтендом, другая над бэкендом, третья над базой данных, — то система будет пронизана такими же разделениями. С игровыми движками будет тоже самое, это зеркало наших коммуникаций внутри студии, компании или команды.
Inverse Conway Maneuver
Чтобы исправить архитектуру софта, Джонни Лерой предложил изменить коммуникации внутри команды. Идея заключается в том, что, чтобы создать более гармоничную архитектуру, необходимо эволюционировать структуру команд и организации параллельно с архитектурой системы. То есть, вместо того чтобы строить систему, которая будет отражать организационные “слабости”, нужно изменить организацию таким образом, чтобы она способствовала созданию более интегрированной и гибкой системы.
Например, если архитектура системы требует тесной интеграции между разными частями — например, между gameplay и render, — то вместо того чтобы заставлять эти команды работать отдельно, надо организовать их так, чтобы они взаимодействовали друг с другом напрямую. Это может включать создание объединенных групп, парное программирование или перекрестные ревью, что приведет к лучшему обмену знаниями и изменению архитектуры.
Unity
Когда я впервые столкнулся с Unity, именно с кишочками движка, а не внешним видом редактора, это был, мягко говоря, шок. Я ожидал от игрового движка, покорившего мир мобилок, вменямой архитектуры, какого-то плана разработки, а вместо этого – увидел лоскутное одеяло компонетов с тремя системами сборки (2014 год, все могло поменяться, но я не слишком в это верю), кое-как собранных вместе и обмазанным клееем в виде mono-vm, лишь бы работало с кучей костылей под платформы и коментов в стиле “Не убирать этот пробел”, “Не компилить в день независимости” или “Сначала собираете с этой константой, если не будет компилиться – ставите 0”. Чтобы собрать двигло и редактор, была отдельная страница вики с расписсанными (не ошибка, 117) шагами, что за чем делать, какие либы собирать первыми, какие пересобрать повторно на шаге Х, какие флаги и опции куда прописывать и кому молиться в случае неудачи.
Но если вы посмотрите на историю возникновения Unity, то вопросов должно стать меньше. Всё началось с разработки собственной игры GooBall, которую в 2001 году задумали студенты Дэвид Хельгасон, Йоахим Анти и Николас Фрэнсис. Их студия Over the Edge Entertainment
столкнулась с типичными проблемами инди-разработчиков начала 2000-х: дорогие лицензии движков, сложный код и отсутствие ресурсов. Ребята игру сделали, но четыре года борьбы закончились провалом, игра не очень то и продавалась. На основе исходников той игры, тех подходов и той команды появился Unity.
В 2005 Unity 1.0 привозят на конференцию Apple, но без громких анонсов. Движок, заточенный под Mac OS X, по идее не должен был взлететь в мире падких на windows игроков. Но именно это стало его козырем: макось всегда была популярна среди дизайнеров, а позже безвариантна среди пионеров мобильной разработки для iPhone. Но движку было что показать, вместо сложных систем программирования там был компонентный подход: объекты собирались как Lego из готовых блоков — физики, анимации, скриптов. Визуальный редактор, редкий для середины 2000-х, позволял буквально перетаскивать мышкой элементы сцены. А поддержка C# и упрощённого UnityScript не заставляла сильно напрягаться при скриптинге. Индустрия движок заметила.
Перелом наступил в 2008-м, когда Unity вышла на Windows, удесятерив аудиторию. Но настоящий взлёт случился два года спустя, после запуска Unity Asset Store — маркетплейса готовых моделей, текстур и скриптов. А учитывая, что большая часть хлама была ценой в бакс, а то и вовсе бесплатной — это стала манной небесной для инди студий и соло энтузиастов. Одновременно движок добавил поддержку iOS и Android, что совпало с бумом смартфонов. Внезапно любой, у кого был ноутбук и идея, мог создать мобильную поделку. Так появились Temple Run (2011) и Monument Valley (2014). Еще через год в 2011 на движок обратили внимание EA, близарды и юбики, заключив долгосрочные контракты на саппорт и лицензировав (фактически купив исходники) для внутреннего использования. К 2015 году почти половина мобильных разработчиков использовала Unity.
Но под капотом это все также оставалось лоскутным одеялом библиотек, трех разных систем сборки, парком велосипедов всего и вся, с частично юзабельными EASTL, boost и стандартной библиотекой плюсов, причем разные части движка могли использовать разные STL, что приводило банально к необходимости копирования данных например между рендером, который жил на EASTL и core редактора, который использовал кастомные классы и контейнеры. Добавьте сюда прибитый сбоку гвоздями Mono, с которым надо было шарить данные и мы получим классическую архитектуру игрового движка начала 2000-х, чтобы быть не слишком “злюкой” – назову такую архитектуру унитарной (Unitary). В англоязычном сегменте есть более точное определение для таких проектов
Big Ball of Mud
Американцы называют такой стиль написания кода без чёткой структуры термином «Big Ball of Mud» — это антипаттерн, описанный в 1997 году Брайаном Футом.
«Big Ball of Mud» — хаотичная, бессистемная, склеенная на скорую руку масса несовместимых компонентов. Такие системы демонстрируют явные признаки бесконтрольного роста и поспешных исправлений. Данные без разбора передаются между удалёнными элементами системы, часто до такой степени, что почти вся важная информация становится глобальной или дублируется.Общая структура системы может никогда не быть чётко определена. Если же она и была, со временем её может размыть до неузнаваемости. Разработчики с хоть каплей архитектурного чутья избегают таких болот. Работать над подобными системами согласны лишь те, кому безразлична архитектура и кто готов мириться с рутиной ежедневных заплаток, едва сдерживающих хаос.
— Брайан Фут
В современных реалиях «унитарная архитектура» может описывать, например, простую игру, где обработчики событий напрямую связаны с вызовами к обрабатывающей логике, без какой-либо внутренней буферизации и диспетчирезации. Большинство игр начинаются так, что в итоге приводят к проблемам неуправляемости по мере роста. Для игры из трех механик и пары экранов это не проблема, но отсутствие структуры в итоге делает изменения все более сложными, а сама система страдает от проблем с деплоем, тестируемостью, масштабируемостью, производительностью.
Такой антипаттерн встречается повсеместно. Редко кто планирует создать «унитарную архитектуру», но многие проекты скатываются к нему из-за отсутствия контроля за качеством и структурой кода. В такой системе любое изменение в одном классе приводит к непредсказуемым побочным эффектам в других, превращая доработки в кошмар. В худшем случае под конец проекта там будет месиво из файлов исходников, ресурсов и технических файлов движка. То, что начиналось как проект трех студентов, сейчас поддерживает команда из 400 инженеров. Компания Unity Technologies состоит из 5000 сотрудников, и менее 10% из них программеры. Ниже представлена схема частей Unity Engine, c виду выглядит прилично и даже неплохо…

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

Не читать
Я уже не первый раз высказываюсь о качестве этого движка, движок отличный для конечного пользователя, иначе бы его не использовало половина мобильных разработчиков, но как вспомню времена починки компилятора шейдеров, хочется поскорее уйти в запой забыть этот кошмар. Не обращайте внимание, это просто нытье и “детские травмы”
Unreal Engine
В 1991 Тим Суини, основатель Epic Games, тогда всего лишь Epic MegaGames, начал создавать инструменты редактирования для своих первых игр. Всё началось с приключенческой игры-головоломки с очень простой графикой под названием ZZT

Там надо было сражаться с различными существами и решать головоломки в лабиринтоподобных уровнях с видом сверху. Используя простые ASCII-символы для визуализации персонажей, врагов и окружения, ZZT работала в текстовом режиме DOS. В то время игра не считалась революционной с точки зрения графики или геймплея, но подход Тима Суини к программированию и особенно встроенный редактор уровней ZZT-OOP заложил принципы модульности, которые впоследствии эволюционировали в Unreal Engine.
В 1992 году Epic выпустила Jill of the Jungle
— платформер для DOS, где появились более продвинутые инструменты вроде анимации спрайтов, физики движения и частиц. Но главным стал акцент на компонентном подходе: Тим использовал структуры данных на основе стандартных компонентов, наверное уже движка, что позволяло переопределять поведение объектов без переписывания всего кода. Можно было создавать новые типы врагов, изменять их AI или добавлять интерактивные элементы уровней через скрипты.

В то время как большинство студий писали код относительно «с нуля» для каждого проекта, подход Тима был в разделении игры на «движок» (низкоуровневые системы рендеринга, физики, звука) и «контент» (ресурсы и логика). Впоследствие этот подход был реализован в Unreal Engine, анонсированном в 1998 году с игрой Unreal, самый первый движок-игра уже состоял из независимых компоментов – common часть, рендер, поверх этого редактор уровня UnrealEd, и отдельно шел скриптовый язык UnrealScript — объектно-ориентированный, с наследованием классов, что упрощало создание модов.

Другие особенности включали физику столкновений с динамическими объектами, 16битный цвет, динамическое освещение до трех источников и запуск игры из редактора уровней. Игра стала огромным успехом, разойдясь тиражом более 1,5 миллиона копий. В 1999 году Epic выпускает свою вторую игру — Unreal Tournament, которая по факту была работой над ошибками, добавив однако встроенную в движок поддержку сети.
Вторая версия Unreal Engine дебютировала в 2002 году с игрой America’s Army — бесплатным многопользовательским шутером, созданым с целью повышения популярности службы. Это был первый случай, когда армия использовала крупномасштабные игровые технологии не для внутреннего использования, мгра даже получила несколько наград, включая “Лучшее использование налоговых денег” от Computer Games Magazine и “Главный сюрприз года” от IGN.
Layered architecture
Многоуровневая архитектура, также известная как n-уровневый или компонентный подход, является одним из наиболее распространенных при организации кода в игровой разработке. Несмотря на то, что Unreal Engine разрабатывался долго в стиле одного конкретного человека, он остался рабочим и для большой команды, обеспечивая структурированность и масштабируемость движка и его часть. Посмотрите на организацию связей между компонентами движка, да, конечно там будут дополнительные связи между разными частями, но их на порядок меньше, и сообщество постоянно фиксит и исправляет выявленные ошибки.

И такая многоуровневая архитектура естественным образом легла на компонентную систему. Каждая компонента, будь то Actor, Blueprint-системы или C++ классы формируют отдельные уровни абстракции, что становится де-факто стандартом разработки и основой архитектуры уже игры для большинства игровых студий, которые используют этот движок.
Основные слои
-
Game-Specific Subsystems
-
Gameplay Foundations
-
Rendering, Profiling & Debugging, Scene Graph / Culling, Visual Effects
-
Skeletal Animation Collision & Physics, Animation
-
AI, HID Audio, Input
-
Resource Manager
-
Core Systems
-
Platform Independence Layer (Networking, File System)
-
3rd Party SDKs (DirectX, OpenGL, PhysX)
-
Hardware
Согласно закону Конвея, структура кода отражает коммуникационную структуру команды разработчиков. Команда Unreal-разработки разделена на небольшие группы: UI и пользовательский ввод, программисты игровой логики (создающие геймплейные системы), инженеры AI, которые отвечают за возможность написания ваших будущих неписей, объектов и монстров, и большая команда инженеров по оптимизации движка. Эта организационная структура естественно переносится с уровня проекта на уровень команды, которая делает непосредственно игру. Отдельные разработчики могут, при желании, выполнять роли в разных группах, а могут стажироваться и переходить из группы в группу, таково политика компании.
Но люди остаются людьми, разработка на Unreal очень расслабляет, и бывает что команды скатываются в “архитектуру по умолчанию”, когда просто следуют шаблонам движка и принятым практиками без особого осмысления зачем это всё надо. Хуже когда в проекте начинается появляться “унитарная архитектура” и команда просто “начинает кодировать” без четкого плана. Какое то время, они неосознанно будут реализовать многоуровневый подход, который несет движок, но без должной структуры и поддержки в итоге все придет к “Big Ball of Mud”.
На 2023 год в Epic Games работает порядка 4,000 сотрудников по всему миру. Это включает команды, занимающиеся играми, издательской деятельностью, магазином и самим движком. По разным оценкам из открытых источников, над движком напрямую работают от 500 до 1,000+ специалистов. Но сюда компания относит, помимо программистов, занимающихся графикой, физикой и оптимизацией (около 200 человек), также инжеров технической поддержки, которые сапортят репо на гитхабе и принимают новые комиты, техписов и инженеров курсов, разработчиков под платформы (VR/AR, мобилки) и большой отдел, который развивает направление Virtual Production, CAD-интеграцию и хотелки крупных игровыйх и кино студий (еще около 400 человек)
Если вам интересно почитать про архитектуры игровых движков, советую обратить внимание на цикл статей про движок Quake.
https://fabiensanglard.net/quake2/quake2_software_renderer.php
https://fabiensanglard.net/quake2/quake2Polymorphism.php
https://fabiensanglard.net/quake2/quake2_software_renderer.php
https://fabiensanglard.net/quake2/quake2_opengl_renderer.php
Microkernel architecture
В начале 2000-х годов, когда разработчики искали пути создания все более реалистичных и иммерсивных игровых миров, на сцене появился уникальный игровой движок с принципиально новым подходом к архитектуре. CryEngine, разработанный немецкой студией Crytek, стал революционным не только благодаря потрясающей графике, но и своей инновационной микроядерной архитектуре.
Всё началось с небольшой демонстрации технологии под названием “X-Isle: Dinosaur Island”
Техно-демка, созданная тремя братьями Йерли (Cevat, Avni и Faruk Yerli), произвела фурор среди издателей и разработчиков. В то время большинство игровых движков основывались на монолитной архитектуре, где компоненты были тесно связаны между собой, но братья имели иное видение. Вдохновленные концепциями QNX, онb перенесли принципы микроядерной архитектуры на игровой движок, что заложило основу для того, что позже превратится в один из самых технологически продвинутых игровых движков своего времени.
Инвесторы и студии поверили в такой подход, когда CryEngine выделяет только критические функции в центральное ядро, а остальные компоненты работают как отдельные модули. Эта модульность позволяла заменять компоненты без риска для стабильности всей системы, причем в какой-то момент были реализации, который позволяли рантайм перегружать отдельные dll прямо во время работы игры, что позволяло например не приостанавливая игру обновлять поведение неписей, чинить логические баги без перезапуска, и только совсем уж критические ошибки приводили к вылету. Но даже в этом случае был фолбек на станадартный модуль, который позволял переподключить вылетевший компонент и продолжить играть. Помимо этого такой подход повзоляет разрабатывать новые функции параллельно, дебажить и оптимайзить подсистемы без необходимости перестраивать весь движок. Братья продвигали идею создания игр различных жанров на одной технологической базе, но что-то не срослось и движок так и остался “лучшим движком для FPS”.
Первой комерческой игрой, продемонстрировавшей мощь микроядерного подхода, стал “Far Cry” (2004), поражавший огромными открытыми пространствами, дальностью прорисовки и реалистичной растительностью, и миром, который мог динамически адаптироваться к действиям игрока. Вторая версия CryEngine, использованный в игре “Crysis” (2007), стала де факто технологическим бенчмарком для новых поколений видеокарт, задав планку графической производительности, а фраза “But can it run Crysis?” стала мемной среди игроков.
Микроядерный подход конкретного движка повлиял на весь игрострой, принеся такие понятия как масштабируемость, отказоустойчивость, адаптивность переноса на новые платформы и архитектуры. Повлиял он и на другие движки, которые начали перенимать отдельные подходы для разработки. Собственно после выхода второго крайзиса масштабируемост и адаптивность стали частью обычных практик в разработке игровых движков в целом.
Современный CryEngine продолжают развивать эти идеи, но уходя больше в сторону всё большего применения искусственного интеллекта для инструментария, ну и конечно графония. Тем не менее, микроядерная философия, заложенная братьями Йерли, повлияла на игровую индустрию, показав, что модульность, гибкость и масштабируемость могут идти вместе с высокой производительностью.
Сейчас движок фактически перешел на оперсорс модель https://github.com/o3de/o3de, который является эволюцией движка Amazon Lumberyard, который, в свою очередь, был основан на CryEngine 2015. Amazon выкупил исходники CryEngine, облагородил сорцы и выложил на гитхаб сначала в виде лицензируемых исходников Lumberyard, а позже и вовсе передал его сообществу в форме O3DE просто так. В движок на момент выход в опенсорс было вбухано порядка 50$ млн, что по некоторым подсчетам будет даже побольше чем у Unity/Unreal, ну или как минимум сравнимо со стоимостью их разработки.

Микромодульная архитектура теперь представлена в виде независимых компонентов-гемов (gem), которые можно произвольно добавлять или удалять из проекта. Amazon и позже сообщество добавили полнофункциональный редактор с визуальными инструментами, который практически не требует программирования, если вы пользуетесь только инструментарием редактора, и скриптовую система (LUA и Python) для создания игровой логики без необходимости разборок с кишочками и C++ кодом. На сегодняшний день O3DE всё ещё находится в активной фазе развития. Хотя движок очень функционален, он не так широко используется как Unreal или Unity.

Dagor

Cреди именитых игровых движков, преимущественно американской прописки, тем не менее есть разработки и от наших ребят, которые оказали значительное влияние на развитие индустрии. Одной из таких технологий стал Dagor Engine, разработанный Gaijin Entertainment. Этот движок примечателен не только своими техническими возможностями и возможностью запускаться на любой картохе (где-то была новость, что его и на эльбрусах запускали), но и уникальным подходом к архитектуре, основанной на data-driven design принципах. Движок сейчас в опенсорсе, так что можете посмотреть сами, что к чему (https://github.com/GaijinEntertainment/DagorEngine)
Движочек начал свою историю в начале 2000-х годов как внутренний инструмент улиток для разработки собственных игр. Стал известен после выхода ависимулятора “Ил-2 Штурмовик: Крылатые хищники” (2009), где продемонстрировал способность обрабатывать сложные физические модели и создавать реалистичные визуальные эффекты, и также показал возможности data-driven подходов.
Data-Driven architecture
Data-driven архитектура — это подход к разработке программного обеспечения, при котором логика приложения определяется преимущественно данными, а не захардкожена в плюсах. В контексте игровых движков это означает, что большая часть игрового мира, объектов и их поведения описывается в файлах данных (часто в формате JSON, XML или других структурированных форматах), которые интерпретируются движком во время выполнения, что несет себе определенные достоинства: разделение данных и кода, декларативное определение (объекты, их свойства и взаимодействия определяются в декларативном стиле, описывающем “что” делать, а не “как” это делать), динамическая конфигурация (изменения вносятся без необходимости перекомпиляции кода и даже перезагрузки игры).
Все эти свойства естесвенным образом вырастают в компонентную систему, которая определяется и конфигурируется через файлы данных. Если в традиционных движках изменение поведения игровых объектов часто требует написания или модификации кода, его компиляции и последующего тестирования, то тут геймдизайнеры и художники могут модифицировать параметры объектов, эффекты и даже базовое поведение, редактируя файлы данных, что называется на лету. Пример, конечно так себе, но я сам видел как на внутреннем турнире по Cuisine Royale админы турнира во время игры спавнили случайные объекты уровня, просто закидывая blk файлы (аналог json) в папку с уровнем, в итоге с неба народу прилетели машины, оружие, холодильники и пара танков. Data-driven архитектура естественным образом поддерживает компонентный подход к проектированию игровых объектов, и со временем сам начинаешь думать в этой парадигме и не представляешь как можно было работать по другому.
Каждый объект в Dagor Engine может быть составлен из набора компонентов, каждый из которых отвечает за определенный аспект функциональности. Этот подход позволяет легко создавать новые варианты объектов путем комбинирования и настройки существующих компонентов, и опять же повторюсь, что всё это делается на лету без перекомпиляции движка и часто даже без перезапуска игры.
Вопреки распространенному мнению о том, что интерпретация данных во время выполнения замедляет игру, правильная реализация data-driven архитектуры может обеспечить высокую производительность. Косвенно, но вы можете судить об этом по возможности запуска игру уровня тундры с приемлимым fps на Nintendo Switch, а это далеко не самое быстрое железо.
Одним из краеугольных камней data-driven архитектуры является система ресурсов. Все игровые данные организованы в виде иерархической структуры конфигов, каждый из которых имеет уникальный идентификатор и может быть загружен по требованию. На примере Dagor Engine может выглядеть так:
/data/
/vehicles/
/tanks/
/t-34/
model.blk
textures/
diffuse.dds
normal.dds
specular.dds
weapons.blk
collision.blk
damage_model.blk
/weapons/
/guns/
/85mm_zis/
ballistics.blk
visual_effects.blk
Файлы .blk
— это специальный формат структурированных данных, используемый в дагоре, который по функциональности похож на JSON, но оптимизирован для быстрой загрузки, обработки и возможностью перегрузки секций и свойств. Игра при подгрузке может перегрузить свойства объекта из версированого конфига, будет выглядеть как-то так, и в финальном конфиге будет rendinstDistMul = 0.8
visual_effects.blk
```
graphics{
enableSuspensionAnimation:b=no
rendinstDistMul:r=0.5
grassRadiusMul:r=0.1
}
```
visual_effects.@1.blk
```
graphics{
override@rendinstDistMul:r=0.8
}
```
Несмотря на все свои преимущества, data-driven архитектура имеет и существенные недостатки. Первое – это сложность отладки – поскольку поведение определяется данными, а не кодом, отладка становится очень трудоемкой, требуя специализированных инструментов для отслеживания того, как изменения в данных влияют на поведение системы, и зачастую приводит к паралленой поддержке визуальных иструментов отладки, спечифичных для конкретного движка. Второе – производительность при интерпретации, хотя движок может быть оптимизирован для эффективной обработки данных, интерпретация данных все равно добавляет накладные расходы по сравнению с хардкодной логикой.
X-Ray Engine и монолитная архитектура
В истории игровой индустрии существует немало технологий, опередивших своё время. Один из них — игровой движок X-Ray, созданный программистами Алексом Максимчуком и Олесем Шишковцом для серии S.T.A.L.K.E.R. Хотя изначально игра должна была быть про роботов на неведомой планете, на которой есть зона с аномалиями и лазеры, но потом ребята поняли, что планету и роботов придумывать не обязательно, а зона с аномалиями и нужной атмосферой находится в трех часах езды на машине от офиса. Впервые продемонстрированный ещё в 2001 году, этот движок стал технологической основой для одной из самых атмосферных игровых вселенных игростроя.
Графическая часть движка впечатляла на момент выхода, высокая детализация — до 4 млн полигонов в кадре, что было намного выше показателей игр даже конца 2000-х, масштабные пространства — движок одинаково эффективно работал как с закрытыми помещениями, так и с открытыми территориями площадью до 2 квадратных километров, динамическая смена времени суток — полноценный цикл день-ночь с соответствующими изменениями освещения и погодные эффекты, вроде реалистичной симуляции дождя, ветра и тумана. Особого внимания заслуживает система динамического освещения, которая даже сегодня выдает запоминающиеся кадры и создает незабываемую атмосферу.
Для физической симуляции X-Ray использовал свободный движок Open Dynamics Engine (ODE), 2001 года выпуска. Эта библиотека с открытым исходным кодом предоставляла систему динамики твёрдого тела и систему обнаружения столкновений, подходила для симуляции транспортных средств, существ и объектов в изменяемом мире. Теоретически, благодаря высокой стабильности интегрирования, система не должна была «взрываться» без причины. Однако игроки первого сталкера хорошо знакомы с многочисленными физическими аномалиями — от летающих тел до странного поведения объектов, что стало своеобразной «фишкой» серии, порождающей мемы и забавные видеоролики, но пусть это будет фишкой зоны, аномалии как никак.
Движок является классическим примером монолитной структуры, не путать с унитарной, разделен на части, связи между которыми хорошо минимизированы. В отличие от других решений, где системы работают относительно независимо, X-Ray представляет собой тесно интегрированную систему, где все компоненты неразрывно связаны.
Монолитная архитектура имеет как определенные преимущества, так и серьёзные недостатки. Тесная интеграция между системами (графика, физика, AI) и возможность создания геймплейных механик, основанных на связях компонентов позволяют более эффективно использовать и планировать ресурсы за счет использования кастомных алокаторов, упаковки объектов, быстрых очередей сообщений и т.д. Прямое взаимодействие между компонентами без дополнительных слоев абстракции обеспечивало максимальную скорость работы на тогдашнем железе. Можно точно управлять памятью и процессорным временем, что было критично для столь требовательного проекта.
Единая архитектура позволяла воплотить целостное видение движка, игрового мира, тулов и подсистем, где всё взаимодействует естественным образом. Проще говоря – это подход к созданию программного обеспечения, при котором различные компоненты системы тесно связаны между собой и функционируют как единое целое и нельзя убрать или выделить отдельную часть без потери функциональности и снижения скорости работы.
Но то, что является сильной стороной в плане перфа, также ограничивает масштабируемость, добавляет сложности обновления отдельных компонентов, вызывает определенные проблемы, особенно на многоядерных системах. Ну и сложность развития такой системы и исправления ошибок в ней растет экспоненциально, так как изменение одной части тянет за собой изменения в соседях.

Собственно сложность и стала главной технической проблемой X-Ray, помимо известных всем фанатам серии случайных вылетов (привет «зелёному жуку»), другой проблемой стали микрофризы и статтеры, наблюдаемые во всех играх серии. Особенно заметными они были в «Тенях Чернобыля» и популярной модификации Misery. В экстремальных случаях игра могла превращаться в слайд-шоу даже при нормальной частоте кадров. Корень проблемы был в архитектуре движка, полагавшегося на ресурсы лишь одного ядра и это ограничение становилось всё более критичным с появлением многоядерных систем.
Официально последней версией движка является X-Ray Engine 1.6.02, использованная в «Зове Припяти». Однако преданное сообщество фанатов не остановилось на этом. Энтузиасты взялись за доработку технологии, создав неофициальные версии движка, в которых были устранены многие критические ошибки, добавлены новые функции и, что особенно важно, реализована поддержка многоядерных процессоров и многопоточности.
Несмотря на технические проблемы, движок остаётся значимой вехой в истории игростроя. Его сильные стороны – динамическое освещение, проработанная физика, система симуляции жизни A-Life – опередили своё время и принесли немало вау-моментов фанатам и возможно этот монолит все же исполнил чье-то желание об игре мечты.
Монолитная архитектура со всеми её преимуществами и недостатками, а главное осмысленное её применение, стало хорошим примером определённого подхода к разработке игровых движков, который тоже является ценным уроком для индустрии. Позже Алекс и Олесь перешли в другую студию, но концепция движка не может измениться одномоменто, да и опыт и наработанные практики тоже, поэтому свое развитие они получили уже в другой серии игр про метро.
Godot и микромодули
Со стороны может показаться, что игродев развивается стремительными темпами: новые подходы к рендеру, применение нейронок для анимаций, формингу моделей и озвучке, но внутри это опирается на опробованные и проверенные решения, сломать или изменить, которые очень и очень не просто. Я бы даже сказал, что игродев за пределами конференций очень консервативен, крупные студии не хотят рисковать, а у мелких на это банально нет средств и времени. Что-то действительно новое в базовых решениях появляется достаточно редко. На этом фоне особенно интересным становится перетаскивание концепций из мира веба, как это вышло с движком Godot и микросервисной архитектурой.

Большинство архитектур получают свои названия постфактум от комьюнити или на конференциях, где замечают определенный шаблон и начинают его развивать — не существует никакой тайной группы архитекторов, которые решают, каким будет следующее крупное движение. Скорее, получается, что многие разработчики в итоге приходят к схожим решениям по мере того, как экосистема движка меняется и развивается. Лучшие способы работы с этими изменениями и извлечения из них пользы становятся архитектурами, которым подражают другие. Микросервисы отличаются в этом отношении, не было движка или игры, который бы использовал такие принципы, и вообще сам термин получил свое название и был популяризирован статьей в блоге Мартина Фаулера и Джеймса Льюиса под названием “Микросервисы”, опубликованной в 2014 году, где они выделили общие характеристики в это относительно новой архитектуре, и я вижу что очень много идей оттуда были переиспользована в Godot. Её суть заключается в разделении сложной системы на множество небольших автономных сервисов, каждый из которых отвечает за конкретную функцию.
В контексте разработки на Godot эта концепция трансформируется в “микромодульную архитектуру”, где игра представляет собой не монолитную махину кода, а систему взаимодействующих компонентов. Физика, искусственный интеллект, пользовательский интерфейс, аудиосистема – каждый из этих элементов может быть реализован как отдельный модуль с чётко определённым интерфейсом взаимодействия. Не скажу, что такой подход видится мне идеальным, но как минимум он позволяет сосредоточиться на отдельных аспектах игры, не беспокоясь о том, как изменения повлияют на другие части проекта.
Движок появился на сцене игродева в 2014 году и с тех пор завоевал сердца многих разработчиков за свою простоту и надежность. Назван он был в честь знаменитого персонажа из пьесы Сэмюэля Беккета “В ожидании Годо”, уникальность Godot заключается в его подходе к организации игровой логики через систему узлов и сцен. Представьте себе конструктор, где каждый элемент игры – от персонажа до интерфейса – это отдельный блок, который можно легко соединять с другими.
Хотя Godot изначально не проектировался с учетом микросервисной архитектуры, его узловая система и модульность хорошо легли на принципы микросервисов. В итоге это все вылилось в микромодульную архитектуру, где различные компоненты могут разрабатываться вообще независимо друг от друга.

Механизм сигналов в Godot предоставляет достаточно интересный способ связывания компонентов. Представьте, что игрок подобрал некий предмет – система инвентаря отправляет сигнал, на который могут реагировать другие системы: интерфейс обновляет отображение, система ачивок обрабатывает прогресс поднятых вещей, а система перков пересчитывает характеристики персонажа, и это при том, что ни одна из этих систем не знает о деталях реализации других, а возможно и об их существовании.
Собственно и основная идея движка состоит в том, что новые функции можно добавлять, создавая новые модули, а не изменяя существующие. Модули-компоненты можно переиспользовать в других проектах, а если модуль содержит ошибку, это с меньшей вероятностью затронет работу всей игры, затронет конечно, игра не может быть супер распределенной, но как минимум падать будет реже.
Но надо помнить, что такая архитектура тоже не является панацеей. Для небольших проектов такой подход оказзывается идеальным, накидываешь модули-компоненты, настраиваешь сигналы и вуаля – все работает в лучшем виде. С ростом проекта, связей и механик они начинают обрастать избыточной сложностью и становятся непродуктивными, система сигналов узким местом, а модули начинают конфликтовать за апдейты. И тут надо понимать, что применение микромодулей оправдано там, где они действительно приносят пользу. Например, отделение игровой логики от визуального представления почти всегда оправдано, в то время как разделение тесно связанных механик на отдельные части-сервисы-модули аукнется позже ненужной сложностью.
Ну и кроме того, в отличие от традиционных микросервисов в веб-разработке, где они работают как отдельные процессы или даже на разных машинах, в игре все компоненты функционируют в рамках одного(нескольких) процесса. Это избавляет от необходимости решать проблемы взаимодействия и синхронизации, которые характерны для классических микросервисных систем и на таких “коротких” дистанциях больше мешают.
Тем не менее, такой подход находит своих фанов, за 2024 год вышло больше десятка относительно крупных игр на этом движке. Это конечно не тысячи как у анриала/юньки, но серьезное достижение для проекта, который ведется фактически пятью людьми и комьюнити.
Что лучше?
Я описал только те движки, с которыми работал на практике достаточно время, но их гораздо больше, и у каждого будет что-то особенное. Хотел бы я знать какой из них лучше, но ответа у меня нет! При таком количестве доступных вариантов, какой именно выбрать — я не знаю. Это зависит от множества факторов внутри проекта и от того, какую игры вы разрабатываете, наличие опыта и людей в команде. Несмотря на всё, что было сказано до этого, есть одно правило, которое применимо к любому проекту и любой архитектуре: делайте игру – выпущенная игра на унитарной архитектуре будет сто крат лучше невыпущенной, на какой бы архитектуре она ни была сделана.
Автор: dalerank