Вебинар: Практическая интеграция PVS-Studio и SourceCraft - 15.07
Книга представляет собой сборник размышлений о языке программирова¬ния C++, алгоритмах и практиках в контексте разработки игр — о его силь¬ных и слабых сторонах, практических решениях и устоявшихся способах работы. C++ на сегодняшний день остаётся основным языком в индустрии разработки игр благодаря сочетанию высокой производительности, гибко¬сти и широких возможностей низкоуровневого контроля.

В начале 2000-х годов, когда разработчики искали пути создания всё более реалистичных и иммерсивных игровых миров, на сцене появился уникальный игровой движок с принципиально новым подходом к архитектуре. CryEngine, разработанный немецкой студией Crytek, стал революционным не только благодаря потрясающей графике, но и своей инновационной микроядерной архитектуре.
Всё началось с небольшой демонстрации технологии под названием "X-Isle: Dinosaur Island". Техно-демка, созданная тогда ещё совсем небольшой командой, произвела фурор среди издателей и разработчиков. В то время большинство игровых движков основывались на монолитной архитектуре, где компоненты были тесно связаны между собой, но братья Йерли (Avni, Faruk и Cevat Yerli) имели иное видение. Вдохновлённые концепциями операционной системы QNX, они перенесли принципы микроядерной архитектуры на игровой проект, в результате появилась основа движка, который позже превратится в один из самых технологически продвинутых для своего времени.
Инвесторы и студии поверили в такой подход, когда CryEngine выделяет только критические функции в центральное ядро, а остальные компоненты работают как отдельные модули. Эта модульность позволяла заменять компоненты без риска для стабильности всей системы, причём в какой-то момент были реализации, которые позволяли прямо во время игры перегружать отдельную логику и подключённые библиотеки, что позволяло обновлять поведение NPC, чинить логические баги без перезапуска, и только совсем уж критические ошибки приводили к крашу. Но даже в этом случае был безопасный обработчик возврата на стандартный модуль, который позволял переподключить вылетевший компонент и продолжить играть. Помимо этого такой подход позволяет разрабатывать новые функции параллельно, отлаживать и оптимизировать подсистемы без необходимости перестраивать весь движок. Братья продвигали идею создания игр различных жанров на одной технологической базе, но что-то не срослось, и движок так и остался "лучшим движком для fps".
Первой коммерческой игрой, продемонстрировавшей мощь микроядерного подхода, стала "Far Cry" (2004), поражавшая огромными открытыми пространствами, дальностью прорисовки и реалистичной растительностью, и миром, который мог динамически адаптироваться к действиям игрока. Вторая версия CryEngine, использованная в игре "Crysis" (2007), оказалась де-факто технологическим бенчмарком для новых поколений видеокарт, задав планку графической производительности, а фраза "But can it run Crysis?" стала мемом среди игроков.
Микроядерный подход конкретного движка оказал влияние на весь игрострой, принеся такие понятия как масштабируемость, отказоустойчивость, адаптивность переноса на новые платформы и архитектуры. Повлиял он и на другие движки, которые начали перенимать отдельные подходы для разработки. Собственно после выхода второго Crysis масштабируемость и адаптивность стали частью обычных практик в разработке игровых движков в целом. На момент появления CryEngine, как и все актуальные для того времени графические движки, был кроссплатформенным. Рендер поддерживал OpenGL, DirectX8/9 и был ориентирован на открытые пространства, один игровой уровень вмещал локации размером до 3 кв. км. Физическая система была собственной разработкой компании, но это нисколько не снизило её качество, поддерживались твёрдые тела, жидкости, транспортные средства, симуляция тканей, мягкотелые объекты, рэгдоллы — для собственной технологии всё было реализовано на высшем уровне.
Технология обратной кинематики (inverse kinematic) позволяла накладывать на модели несколько анимаций одновременно для создания реалистичного поведения. За искусственный интеллект NPC отвечал модуль на Lua вместо C++, причём его особенность состояла в том, что скрипты не требовали перекомпиляции. В целом, этот движок подарил нам Far Cry с множеством дополнений, а также многопользовательскую ролевую игру AION. Разработчики из NCSoft приобрели CryEngine для своей MMO, хотя впоследствии они сильно переработали его под свои нужды, оптимизировав с учётом особенностей многопользовательских онлайн-игр.
В 2002 году после релиза движка и выхода Far Cry в модуль шейдеров добавлена поддержка шейдеров версии 3.0, а версия движка получила название 1.2. Шейдеры позволили реализовать множество визуальных эффектов: поканальное освещение, отражения с неровностями, преломления, дым, анимированные текстуры, прозрачные экраны компьютеров, окна, следы от пуль. Особенностью была реализация тумана, который оказался намного более реалистичным по сравнению с другими движками того времени.
В марте 2006 года компания Ubisoft приобрела все права на CryEngine, также были выкуплены все права на игру Far Cry. Ubisoft получила права использования на всю интеллектуальную собственность, включая товарный знак, логотип, персонажей, сюжет, франшизу, сеттинг, а также исключительные права на исходный код и реализованные технические решения, т. е. ребята не могли пользоваться старым кодом для разработки нового движка.
Таким образом, с этого момента Crytek больше не имела никаких юридических или правовых связей с движком и не могла использовать ни сам движок, ни торговую марку CryEngine. После выпуска всех патчей от Crytek для игры Far Cry, движок начал развиваться в двух направлениях. Поскольку ранее Ubisoft приобрела все права на CryEngine и Far Cry, она продолжила разработку собственного варианта движка — для игр Far Cry Instincts и Far Cry Instincts: Evolution на Xbox, Far Cry Instincts: Predator на Xbox 360, а также Far Cry Vengeance для Nintendo Wii. Как заявил в официальном интервью Луи-Пьер Фаран (Louis-Pierre Farand), ведущий продюсер Far Cry 2, движок Dunia Engine использует лишь 2–3% исходного кода оригинального CryEngine (рис. 2.7).

Рисунок N2.7
В свою очередь, специалисты Crytek продолжили развивать собственную технологическую базу и разработали новый движок — CryEngine 2, который стал следующей эволюцией оригинального CryEngine, полностью независимой от Ubisoft. Как и его предшественник, он был написан на C++, однако его главное отличие — отсутствие кроссплатформенности. Единственная поддерживаемая платформа — операционная система Windows с поддержкой DirectX. На момент своего выхода CryEngine 2 был одним из самых технологически продвинутых и фотореалистичных графических движков по сравнению с конкурентами, устанавливая новые стандарты в области визуализации, физики и динамических сред. Однако его высокие системные требования и привязка к Windows/DirectX ограничили аудиторию до владельцев мощных игровых ПК.
Поддержка всех возможностей предыдущей версии осталась, даже улучшилась — CryEngine 2 так же хорошо справляется с огромными открытыми пространствами, вдобавок появилась система потоковой загрузки ресурсов (стриминга), которая позволила заполнять уровни по мере продвижения игрока. Разработчики Crytek одними из первых перешли к использованию 64-разрядной архитектуры. Поскольку размер игровых уровней увеличился со времён FarCry, то и затраты ресурсов на их отрисовку значительно возросли, что приводило к невозможности работать на 32-разрядных системах.
Микроядро также никуда не делось, все дополнительные модули хранятся в DLL-файлах и используются по мере необходимости во время игры. Скомпилированный движок расположен в отдельных DLL-файлах, каждый компонент движка находится в отдельном файле-библиотеке, что позволяет задействовать компоненты выборочно, модифицируя и заменяя только те компоненты, которые в этом нуждаются, а не весь движок целиком.
Новый физический движок также был разработан внутри CryTek (CryPhysics) и отличался изначальной ориентированностью на многопоточную обработку и полностью интегрирован в CryEngine 2. Это позволило осуществлять разнообразные манипуляции с физикой и применять физику практически ко всем объектам на уровне, включая деревья и растительность, для создания реалистичной реакции объектов на разные воздействия (гравитация, ветер, взрывы, трение, столкновения с другими объектами).
Переход к третьей версии, как и раньше, сопровождался внутренними конфликтами в команде и на уровне менеджмента. Разработкой занималась уже совсем другая группа, поэтому движок способен и приятно удивить, и вызвать разочарование. CryEngine 3 был официально анонсирован 11 марта 2009 года, а его релиз состоялся 14 октября того же года. Первой игрой на новом движке стал шутер от первого лица Crysis 2.
Изначально сам движок был написан с поддержкой DirectX 11, но первая игра, выпущенная на нём, полностью игнорировала этот API, как и DirectX 10, до выхода соответствующего патча, который исправил ситуацию. Скорее всего, компания поступила так потому, что хотела сделать Crysis 2 кроссплатформенной, ведь главным недостатком эксклюзивности для ПК было то, что на каждую купленную копию игры приходилось 10 пиратских загрузок, в результате особое внимание было уделено консолям.
В современном CryEngine 3 продолжают развивать идеи микроядерной архитектуры, постепенно уходя в сторону всё большего применения искусственного интеллекта для инструментария, ну и конечно графики. Тем не менее, философия, заложенная братьями Йерли, повлияла на игровую индустрию, показав, что модульность, гибкость и масштабируемость могут идти вместе с высокой производительностью. Сейчас движок фактически перешёл на модель с открытым исходным кодом, которая является эволюцией движка Amazon Lumberyard, который, в свою очередь, был основан на CryEngine 2015, исходники последнего выложены отдельно.
Разработчики Amazon выкупили исходники CryEngine, облагородили исходные файлы проекта и выложили на GitHub сначала в виде лицензируемых исходников Lumberyard, а позже и вовсе передали его сообществу в форме O3DE просто так. На момент выхода в опенсорс на движок было потрачено более 50 млн. долл., что по некоторым подсчётам будет даже побольше чем у Unity/Unreal, ну или как минимум сравнимо со стоимостью их разработки. Микромодульная архитектура теперь представлена в виде независимых компонентов-гемов (gem), которые можно произвольно добавлять или удалять из проекта (рис. 2.8).
На сегодняшний день O3DE всё ещё находится в активной фазе развития, и, хотя движок очень функционален, он не так широко используется как Unreal или Unity.

Рисунок N2.8
Среди именитых игровых движков, преимущественно американской прописки, тем не менее, есть разработки и от ребят из Восточной Европы, которые оказали значительное влияние на развитие индустрии. Одной из таких технологий стал Dagor Engine, разработанный Gaijin Entertainment. Этот движок примечателен не только своими техническими характеристиками и возможностью запускаться на любой платформе, где есть видеокарта и хоть какой-нибудь процессор, но и уникальным подходом к архитектуре, основанной на принципах data-driven design. Движок сейчас в открытом доступе, так что можете посмотреть сами, что к чему.
История этого движка началась в начале 2000-х годов, когда внутренний инструмент для разработки игр стал известен после выхода авиасимулятора "Ил-2 Штурмовик: Крылатые хищники" (2009), продемонстрировав способность обрабатывать сложные физические модели и создавать реалистичные визуальные эффекты, и также показав возможности data-driven подходов.
Data-driven архитектура — это подход к разработке программного обеспечения, при котором логика приложения определяется преимущественно данными, а не за-писана в исходниках. В контексте игровых движков это означает, что большая часть игрового мира, объектов и их поведения описывается в файлах данных (часто в формате JSON, XML или других структурированных форматах), которые интерпретируются движком во время выполнения, что даёт определённые достоинства: разделение данных и кода, декларативное определение (объекты, их свойства и взаимодействия определяются в декларативном стиле, описывающем "что" делать, а не "как" это делать), динамическая конфигурация (изменения вносятся без необходимости перекомпиляции кода и даже без перезагрузки игры). Все эти свойства естественным образом вырастают в компонентную систему, которая определяется и конфигурируется через данные.
Если в традиционных движках изменение поведения игровых объектов часто требует написания или модификации кода, его компиляции и последующего тестирования, то тут игровые дизайнеры и художники могут модифицировать параметры объектов, эффекты и даже базовое поведение, редактируя файлы данных, что называется "на лету". На внутреннем турнире по одной из игр студии, админы во время игры создавали случайные объекты уровня, просто закидывая 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
/weapons/
/guns/
/85mm_zis/ ballistics.blk Visual_effects.blk
Файлы *.blk — это специальный формат структурированных данных, используемый в этом движке, который по функциональности похож на JSON, но оптимизирован для быстрой загрузки, обработки и возможности перегрузки секций и свойств. Игра при подгрузке может перегрузить свойства объекта из другого конфига. Всё будет выглядеть примерно так:
visual_effects.blk graphics {
rendinstDistMul:r=0.5 grassRadiusMul:r=0.1
}
visual_effects.@1.blk graphics {
override@rendinstDistMul:r=0.8
}
И в финальном конфиге будет rendinstDistMul = 0.8.
Несмотря на все свои преимущества, архитектура data-driven обладает и существенными недостатками. Первое — это сложность отладки, поскольку поведение определяется данными, а не кодом, отладка становится очень трудоёмкой, требуя новых инструментов для отслеживания того, как изменения в данных влияют на поведение системы, и зачастую приводит к параллельной поддержке визуальных инструментов отладки, специфичных для конкретного движка.
Второе — снижение производительности при интерпретации. Хотя движок может быть оптимизирован для эффективной обработки данных, интерпретация данных всё равно добавляет накладные расходы по сравнению с хардкодной логикой.
На рис. 2.9 показаны системы, которые могут быть сконфигурированы через изменение скриптов без необходимости пересобирать весь движок, и, как можно заметить, это почти весь движок.
В истории игровой индустрии существует немало технологий, опередивших своё время. Один из примеров — игровой движок X-Ray, созданный программистами Александром Максимчуком и Олесем Шишковцом для серии S.T.A.L.K.E.R. Хотя изначально игра задумывалась про роботов на неведомой планете, на которой есть зона с аномалиями и лазеры, но потом ребята поняли, что планету и роботов придумывать не обязательно, а зона с аномалиями и нужной атмосферой находится в трёх часах езды на машине от офиса.

Рисунок N2.9
Впервые продемонстрированный ещё в 2001 году, этот движок стал технологической основой для одной из самых атмосферных игровых "вселенных". Графическая часть движка впечатляла на момент выхода. Высокая детализация — до 4 млн полигонов в кадре, что было намного выше показателей игр даже конца 2000-х, масштабные пространства — движок одинаково эффективно работал как с закрытыми помещениями, так и с открытыми территориями площадью до 2 кв. км, динамическая смена времени суток — полноценный цикл день-ночь с соответствующими изменениями освещения и погодные эффекты, вроде реалистичной симуляции дождя, ветра и тумана. Особого внимания заслуживает система динамического освещения, которая даже сегодня выдаёт запоминающиеся кадры и создаёт незабываемую атмосферу.
Для физической симуляции X-Ray использовал свободный движок Open Dynamics Engine (ODE), 2001 года выпуска. Эта библиотека с открытым исходным кодом предоставляла систему динамики твёрдого тела и систему обнаружения столкновений, подходила для симуляции транспортных средств, существ и объектов в изменяемом мире. Теоретически, благодаря высокой стабильности интегрирования, система не должна была "взрываться" без причины. Однако игроки первого сталкера хорошо знакомы с многочисленными физическими аномалиями — от летающих тел до странного поведения объектов, что стало своеобразной "фишкой" серии, порождающей мемы и забавные видеоролики, но пусть это будет особенностью зоны, аномалии как-никак.
Этот движок — классический пример монолитной структуры (не путать с унитарной), разделён на части, связи между которыми хорошо минимизированы. В отличие от других решений, где системы работают относительно независимо, X-Ray представляет собой тесно интегрированную систему, где все компоненты неразрывно связаны.
Монолитная архитектура (рис. 2.10) имеет как определённые преимущества, так и серьёзные недостатки. Тесная интеграция между системами (графика, физика, AI) и возможность создания геймплейных механик, основанных на связях компонентов, позволяют более эффективно использовать и планировать ресурсы за счёт применения кастомных аллокаторов, упаковки объектов, быстрых очередей сообщений и т. д. Прямое взаимодействие между компонентами без дополнительных слоёв абстракции обеспечивало максимальную скорость работы на тогдашнем железе. Можно точно управлять памятью и процессорным временем, что было критично для столь требовательного проекта.
Единая архитектура позволяла воплотить целостное видение движка, игрового мира, инструментов разработки и подсистем, где всё взаимодействует естественным образом. Проще говоря — это подход к созданию программного обеспечения, при котором различные компоненты системы тесно связаны между собой и функционируют как единое целое и нельзя убрать или выделить отдельную часть без потери функциональности и снижения скорости работы.
Но то, что является сильной стороной в плане производительности, также ограничивает масштабируемость, добавляет сложности обновления отдельных компонентов, вызывает определённые проблемы, особенно на многоядерных системах. Ну и сложность развития такой системы и исправления ошибок в ней растёт экспоненциально, т. к. изменение одной части тянет за собой изменения в соседях.
Собственно сложность и стала главной технической проблемой X-Ray, помимо известных всем фанатам случайных вылетов (привет "зелёному жуку"), другой неприятностью стали микрозависания и подтормаживания (подёргивания картинки), наблюдаемые во всех играх серии. Особенно заметными они были в "Тенях Чернобыля" и в экстремальных случаях игра могла превращаться в слайд-шоу даже при нормальной частоте кадров. Корень проблемы был в архитектуре движка, полагающегося на ресурсы лишь одного ядра, и это ограничение становилось всё более критичным с появлением многоядерных систем.

Рисунок N2.10
Официально последней версией движка является X-Ray Engine 1.6.02, использованная в "Зове Припяти". Однако сообщество фанатов не остановилось на этом — энтузиасты взялись за доработку технологии, создав неофициальные версии движка, в которых были устранены многие критические ошибки, добавлены новые функции и, что особенно важно, реализована поддержка многоядерных процессоров и многопоточности.
Несмотря на технические проблемы, движок остаётся значимой вехой в истории игростроя. Его сильные стороны — динамическое освещение, проработанная физика, система симуляции жизни A-Life — опередили своё время и принесли немало вау-моментов фанатам, и возможно этот монолит всё же исполнил чье-то желание об "игре мечты".
Монолитная архитектура со всеми её преимуществами и недостатками, а главное осмысленное её применение, — хороший пример определённого подхода к разработке игровых движков, который тоже является ценным уроком для индустрии. Позже концепция движка и наработанные практики своё развитие получили уже в другой серии игр по вселенной Метро 2033.
Со стороны может показаться, что игрострой развивается стремительными темпами: новые подходы к рендеру, изменению скелетов, внешнего вида моделей и озвучке, применение нейротехнологий для анимаций, но внутри всё это опирается на опробованные и проверенные решения, сломать или изменить которые очень и очень не просто. Я бы даже сказал, что за пределами конференций разработка игр очень консервативна, крупные студии не хотят рисковать, а у мелких на это банально нет средств и времени. Что-то действительно новое в базовых решениях появляется достаточно редко. На этом фоне особенно интересным становится перетаскивание концепций из мира веба, как это вышло с движком Godot и микросервисной архитектурой.
Большинство архитектур получают свои названия постфактум от комьюнити или на конференциях, где замечают определённый шаблон и начинают его развивать — не существует никакой тайной группы архитекторов, которые решают, каким будет следующее крупное движение. Скорее, получается, что многие разработчики в итоге приходят к схожим решениям по мере того, как экосистема движка меняется и развивается. Лучшие способы работы с этими изменениями и извлечения из них пользы становятся архитектурами, которым подражают другие. Микросервисы отличаются в этом отношении, поскольку на момент их появления не было движка или игры, который бы использовал такие принципы, и вообще сам термин получил своё название и был популяризирован статьёй в блоге Мартина Фаулера и Джеймса Льюиса под названием "Микросервисы", опубликованной в 2014 году, где они выделили общие характеристики этой относительно новой архитектуры, и я вижу, что очень много идей оттуда были переиспользованы в Godot. Её суть заключается в разделении сложной системы на множество небольших автономных сервисов, каждый из которых отвечает за конкретную функцию.
В контексте разработки на Godot эта концепция трансформируется в "микросервисную архитектуру", где игра представляет собой не монолитную "махину" кода, а систему взаимодействующих компонентов. Физика, искусственный интеллект, пользовательский интерфейс, аудиосистема, — каждый из этих элементов может быть реализован как отдельный модуль с чётко определённым интерфейсом взаимодействия. Не скажу, что такой подход видится мне идеальным, но как минимум он позволяет сосредоточиться на отдельных аспектах игры, не беспокоясь о том, как изменения повлияют на другие части проекта.
Движок появился на сцене в 2014 году и с тех пор завоевал сердца многих разработчиков за свою простоту и надёжность. Назван он был в честь знаменитого персонажа из пьесы Сэмюэля Беккета "В ожидании Годо", уникальность Godot заключается в его подходе к организации игровой логики через систему узлов и сцен. Представьте себе конструктор, где каждый элемент игры — от персонажа до интерфейса — это отдельный блок, который можно легко соединять с другими. Хотя Godot изначально не проектировался с учётом микросервисной архитектуры, его узловая система и модульность хорошо легли на принципы микросервисов. В итоге это всё вылилось в архитектуру, где различные компоненты могут разрабатываться вообще независимо друг от друга.
Механизм сигналов в Godot предоставляет достаточно интересный способ связывания компонентов. Представьте, что игрок подобрал некий предмет, — система инвентаря отправляет сигнал, на который могут реагировать другие системы: интерфейс обновляет отображение, система достижений обрабатывает прогресс поднятых вещей, а система уникальных способностей пересчитывает характеристики персонажа, и ни одна из этих систем не знает о деталях реализации других, а возможно и об их существовании.
Собственно и основная идея движка состоит в том, что новые функции можно добавлять, создавая новые модули, а не изменяя существующие. Модули-компоненты можно повторно использовать в других проектах, а если модуль содержит ошибку, это с меньшей вероятностью отразится на работе всей игры, затронет, конечно, игра не может быть чрезмерно распределённой, но как минимум "падать" будет реже.
Но надо помнить, что такая архитектура тоже не является панацеей. Для небольших проектов подобный подход оказывается идеальным: накидываешь модули-компоненты, настраиваешь сигналы и вуаля — всё работает в лучшем виде. С ростом проекта, связей и механик всё начинает обрастать избыточной сложностью и становится непродуктивным, система сигналов превращается в узкое место, а модули начинают конфликтовать за обновления. И тут надо понимать, что применение микромодулей оправдано там, где они действительно приносят пользу. Например, отделение игровой логики от визуального представления почти всегда оправдано, в то время как разделение тесно связанных механик на отдельные части-сервисы-модули аукнется позже ненужной сложностью.
Ну и кроме того, в отличие от традиционных микросервисов в веб-разработке, где они работают как отдельные процессы или даже на разных машинах, в игре все компоненты функционируют в рамках одного (нескольких) процесса. Это избавляет от необходимости решать проблемы взаимодействия и синхронизации, которые характерны для классических микросервисных систем, и на таких "коротких" дистанциях больше мешают.
Тем не менее, описанный подход находит своих фанатов: за 2024 год вышло больше десятка относительно крупных игр на этом движке. Это конечно не тысячи как у Unreal/Unity, но серьёзное достижение для проекта, который ведётся фактически пятью людьми и комьюнити.
Автор — Сергей Кушниренко
Разработчик с более чем двадцатилетним опытом программирования и создания игр. Выпускник Национального исследовательского университета ИТМО. Начинал карьеру с разработки программного обеспечения для военно-морских тренажеров, навигационных систем и сетевых решений. Последние пятнадцать лет специализируется на разработке игр: в Electronic Arts занимался оптимизацией игр The Sims и SimCity BuildIt, в Gaijin Entertainment руководил переносом игр на платформы Nintendo Switch и Apple TV. Активно участвует в проектах с открытым исходным кодом, включая библиотеку ImSpinner и проект восстановления игры Pharaoh (1999).
Game++. Часть 1.1: С++, движки и архитектуры
0