1 / 70

Архитектурные особенности систем разработки консольных и многоплатформенных игр

Архитектурные особенности систем разработки консольных и многоплатформенных игр. Руслан Абдикеев Jaleco Entertainment mailto: ruslan@vr1.spb.ru http://www.jaleco.com. Системы разработки игр. Задачи и характеристики Типичные архитектурные решения Ключевые проблемы Пути решения проблем

Download Presentation

Архитектурные особенности систем разработки консольных и многоплатформенных игр

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Архитектурные особенности систем разработки консольных и многоплатформенных игр Руслан Абдикеев Jaleco Entertainment mailto: ruslan@vr1.spb.ru http://www.jaleco.com

  2. Системы разработки игр • Задачи и характеристики • Типичные архитектурные решения • Ключевые проблемы • Пути решения проблем • Примеры

  3. Уточнение • Разработка консольных или кроссплатформенных игр – огромная тема • Планирование • Организация производственного процесса • Подготовка контента • Переносимость кода и функциональности • Ограничения конкретных консолей • Различия в TCR/TRC

  4. Уточнение (2) • Консоли предъявляют жесткие требования к распределению ресурсов во время игры • Консольные игры предполагают более жесткий quality assurance и более жесткие требования к целостности контента • Решения, применяемые в современных технологических цепочках, не лучшим образом сказываются на масштабируемости и производительности движка

  5. Уточнение (3) • Основные темы: • Снижение накладных расходов при сохранении гибкости и расширяемости архитектуры • Способы эффективного представления контента в памяти и на диске • Механизмы настройки контента • Вопросы гарантии целостности ресурсов • Большая часть материала применима и к разработке игры для одной платформы, в частности, для PC

  6. Мотивация: отраслевые тенденции • Стремительное развитие технологий • Резкое усложнение игрового контента • Самые разнообразные платформы • «Переход количества в качество» • Вытеснение «гаражных» методов разработки промышленными

  7. Мотивация: ожидания потребителей • Покупают не технологию, а контент • Но ожидают кинематографическое качество • Большой и сложный мир, живущий сам по себе • Выразительные и эмоциональные персонажи • Предельная интерактивность • Поведение, анимация, звук, изображение…

  8. Мотивация: требования издателей • Минимум рисков, связанных с производством • Сокращение цикла разработки для ускорения выхода на рынок • Повторная используемость контента (перенос на другие платформы, сиквелы) • Разумный бюджет • Поддержка новых технологий - подразумевается

  9. Характеристики системы разработки игр • Простота внедрения • Гибкость и расширяемость • Масштабируемость • Производительность

  10. Типичные архитектурные решения • Абстрагирование, расцепление (decoupling) • Компонентные архитектуры • Архитектуры, управляемые данными • Скрипты • Обобщенный формат хранения контента • «Добавление уровня косвенности решает большинство проблем»

  11. Компонентные архитектуры • Подключаемые (plug-in) модули • Сложные динамические системы из простых компонент • Построение платформы для будущих расширений

  12. Компонентные архитектуры (2) • Уменьшение «зацепления» кода • Повторное использование компонент • Много игр – одна кодовая база • Композиция компонент – комбинаторный взрыв возможностей

  13. Data driven архитектуры • Инкапсуляция структуры игрового мираи настроек его компонентов • Основное время разработки игры – создание контента и его настройка • Игра – база данных, не надо фиксировать ее в коде • Оставьте программистов в покое! • Быстрый цикл идея-проверка-внедрение

  14. Data driven архитектуры (2) • Данными легче управлять, чем кодом • У данных меньше «зацепление»,чем у кода • Схема: объект = шаблон + настройки • Жестче схема – меньше ошибок • Данные легче поддаются автоматической обработке: сборке ресурсов, переносу на другие платформы

  15. Data driven архитектуры (3) • Единообразные инструменты • Меньше инструментов – больше областей их применения • Композиция атрибутов и структурная композиция – комбинаторный взрыв возможностей

  16. Скрипты • Инкапсуляция поведения элементов системы • Мы даже код сделаем данными™ • Оставьте программистов в покое! • Быстрый цикл идея-проверка-внедрение

  17. Скрипты (2) • Высокоуровневые примитивы языка, специфичные для игровых задач • Естественный доступ к функциональности движка • Виртуальная машина, компактное представление, JIT-компиляция • Перенос на другие платформы

  18. Обобщенный формат хранения • Сериализация/десериализация • Компоненты + данные • Все равно, что, где и как хранить • Единообразие и прозрачность • Некоторые гарантии целостности

  19. Результаты • Вроде бы, все хорошо • Гибкость, расширяемость • Производительность технологической цепочки • Единообразный подход к компонентам игрового мира и их атрибутам • Но…

  20. Пиррова победа? • Чрезмерная общность • Высокие издержки, «over engineering» • Неформальные «договоренности» • Явные спецификации недостаточно формализованы или отсутствуют • Связи кода со внутренней структурой 3D моделей и сцен • Что и как часто мы будем изменять или использовать • Естественные последствия требований гибкости и расширяемости

  21. Пиррова победа? (2) • Еще раз: большой и сложный мир… • Высокая степень детализации контента • Какова цена единообразного подхода к атрибутам системы? • «Грубый помол»? • Масштабируемость тех. цепочки? • Масштабируемость движка? • Какова цена неформальных договоренностей? • Целостность ресурсов? • Масштабируемость тех. цепочки? • Производительность движка?

  22. Два детальных примера • Хранение 3D сцен на диске и их представление в памяти • Настройка контента и доступ к параметрам игровых объектов из игры

  23. Case 1: представление 3D моделей • Типичные схемы: • Монолитное представление • Слишком жесткое, но эффективное • Открытое (компонентное) представление • Слишком гибкое, но расточительное и хрупкое • Нам нужна золотая середина • Не платим за то, что не используем • Требуем гарантий целостности

  24. 3D: монолитное представление • «Классика жанра»: Quake • При разработке движка фиксируется набор управляемых атрибутов конкретных моделей (как правило, только скины и анимации) • Жесткие правила именования (тэги или имена подобъектов) • При экспорте – преобразование в жестко заданный для этого типа моделей формат (Quake .MD3для моделей игроков, например) • У моделей не может быть развитой внутренней структуры • нет разнородных атрибутов – нет проблемы

  25. 3D: открытое представление • Scene graph, DAG, дерево подобъектов • Доступны все атрибуты всех объектов в иерархии (в т.ч. атрибуты шейдеров) • Разнородные (гетерогенные) данные • Обобщенный, независимый от типа модели и target платформы формат • Произвольный доступ к модели со стороны игровых объектов • Как правило, компонентная архитектура

  26. 3D: открытое представление (2) • Существуют правила именования подобъектов и их атрибутов • Чаще всего, неявные правила («изустное творчество»), поскольку игровой код отделен от инструментов по созданию контента • Неявные правила – неформальные договоренности

  27. 3D: открытое представление (3) • «Слишком» гибкое представление • Наши намерения не выражены явно • Весь спектр классических проблем ОО: • Некомпактное представление объектов • Медленная загрузка • Обилие перераспределений памяти • Фрагментация памяти • Высокий расход памяти и медленное копирование объектов: движок не знает, какие данные мы можем изменить

  28. 3D: открытое представление (4) • Статические объекты могут быть представлены более эффективно • Но оптимизатор не знает, что мы будем изменять • Нет гарантий целостности ресурсов • Пока есть «неформальные договоренности», автоматическая проверка целостности невозможна

  29. 3D: открытое представление (5) • Игровой код: уродлив, неэффективен, подвержен ошибкам // получение бокса левого закрылка render::noden = Plane.find_node_recursive(“FlapsLeft”); assert( n != null ); render::mesh m = (render::mesh)n.get_robject(); assert( m != null ); render::box b = m.get_box(); • Заранее известно, что левый закрылок должен присутствовать в модели • Известно, что нужен только бокс закрылка

  30. 3D: открытое представление (6) • Игровой код: хотелось бы что-то подобное: // получение бокса левого закрылка render::boxb = Plane.FlapsLeft.box; • Более красиво, более эффективно • Целостность данных должна проверяться раньше, не во время исполнения

  31. Вседозволенность против гибкости • Абстрагирование и позднее связывание вызывают потери неявной информации о структуре связей кода с контентом • Она как бы есть, но скрытая, недоступная для внешних (управляемых данными) инструментов • Для консольных игр такие потери плюс «неформальные договоренности» могут стать фатальными • Сходная проблема есть в языках программирования как оборотная сторона ОО и как пример «abstraction penalty»

  32. Вседозволенность: Стек на C# class Stack { public void Push( object item ); public object Pop(); } Stack s = new Stack(); s.Push( (object)123 ); int n = (int)s.Pop(); • Слишком гибок: стек любых объектов • Не соответствует задаче: нам нужен стек int • Дорог и некрасив: преобразование в/из object’а • Не дает гарантий целостности: о несоответствии типов станет известно только в run-time

  33. Гибкость: Стек на C# с Generics class Stack<T> { public void Push( T item ); public T Pop(); } Stack<int> s = new Stack<int>(); s.Push( 123 ); int n = s.Pop(); • «Заточенность»: стек int – ровно то, что нужно • Эффективность: нет преобразований • Целостность: ошибки типов диагностируются во время компиляции

  34. 3D: явная параметризация • Явная параметризация типов в языках программирования переносит время связывания на момент компиляции и дает: • Эффективность • Удобство • Гарантии целостности • При этом сохраняя гибкость и расширяемость

  35. 3D: открытое представление (7) // получение бокса левого закрылка render::boxb = Plane.FlapsLeft.box; • Это не должен быть «синтаксический сахар» скриптового языка, скрывающий неэффективную и хрупкую реализацию • Это должно быть именно представление модели в памяти, поэтому результаты должны быть применимы и к C++ коду • Перенос времени связывания с run-time на момент компиляции кода (compile-time) и на момент сборки ресурсов (bundler-time) • Ранняя и 100% диагностика ошибок

  36. 3D: явная параметризация (2) • Введем в движок описание 3D моделей: game FighterAce { scene Plane { instance LaGG3 “ЛаГГ-3”; instance P38L “P-38L”; readonly FlapsLeft.box = Mesh(“FlapsLeft”).Box; } } • Описание задает как атрибуты объектов, используемые/модифицируемые игровым кодом, так и требования к 3D моделям

  37. 3D: явная параметризация (3) • Для архитектур, управляемых данными, – это естественный шаг • Требования к модели используются при экспорте, оптимизации и сборке ресурсов • Информация о связях игрового кода с 3D моделью используется для формирования эффективного memory layout и удобного интерфейса к объекту

  38. 3D: назад к монолитам • Фактически, мы возвращаемся к «жестким» монолитным форматам хранения 3D моделей • Автоматически генерируемые форматы, «заточенные» под конкретную комбинацию модель-платформа • Работа с этимиформатами происходит прозрачно и полностью автоматически для игрового кода • Внутренние атрибуты моделей доступны в естественной для игрового кода форме

  39. 3D: memory layout • В соответствии с описанием 3D модели, все ее атрибуты разбиваются на два класса: • Разделяемые атрибуты, общие для всех копий • Копируемые атрибуты, в частности, атрибуты, изменяемые игровым кодом • Мы можем распределить всю 3D модель (исключая ресурсы рендера) в два непрерывных участка памяти • Компактное, cache friendly представление • Идеально для фоновой загрузки и копирования

  40. 3D: детали • Автоматически генерируемый для игровых объектов интерфейс работы с 3D моделью (общая идея): classPlane : public render::u_object { public: struct FlapsLeft_t { render::box8 box; }; enum instance_t { LaGG3, P38L } instance; FlapsLeft_t FlapsLeft; staticPlane* Load( instance_t inst ); Plane* Copy() const; voidDestroy(); };

  41. 3D: детали (2) • Формат представления конкретной модели определяется файлом описания и собственно содержимым 3D сцены • Для каждого файла описания генерируется .h и .cpp • .cpp – assertions и зависящий от описания моделикод • На диске данные представлены в готовом к употреблению виде (относительная адресация) с таблицей fix up • Загрузка – чтение с диска в непрерывный участок памяти, применение fix up и создание C++ объектов(placement new)

  42. 3D: детали (3) • Движок (включая рендер) работает со структурой, близкой к scene graph • Объекты движка не имеют фиксированного memory layout (любой атрибут может попасть в пользовательскую область) • Адресация через аналог v-table • Тем не менее, естественная C++ нотация (благодаря средствам языка вроде template) • Скорость работы движка выше из-за дружественной к кэшу структуры

  43. 3D: голые факты • Считаем только пользовательскую часть, без звуков и 3D ресурсов • Не самый худший случай • Один самолет B-17 (без панели кабины) • Около 50 подобъектов, анимированных художниками • Около 100 атрибутов, изменяемых из игры (преимущественно матрицы трансформации, флаги видимости, контроллеры анимаций)

  44. 3D: голые факты • Вседозволенность: • Одна копия: около 80K в 140 блоках • Разделяемые данные: около 700K в 170 блоках • Создание копии на PC вызывает легкие лаги и swap при недостаточном объеме памяти • Применялись аллокаторы, умные указатели и т.п. • Гибкость с явными намерениями: • Одна копия: 12K в 1 блоке • Разделяемые данные: 256K в 1 блоке • Прямое чтение с диска с последующим fix up • Скорость копирования сравнима с memcpy() • Никаких аллокаторов (выделение по 4K) • Никаких умных указателей

  45. Case 1: результаты • Высокая производительность • Минимальные требования к ресурсам • Отсутствие сложного lifetime management • Эффективная работа с памятью • Полностью автоматическая сборка • 100% гарантии целостности ресурсов • Ясный, простой и эффективный игровой код • Сохранены гибкость и расширяемость

  46. Case 1: заключение • Обобщенный формат используется для хранения и трансформаций контента • Сборщик ресурсов • Выполняет низкоуровневую оптимизацию под конкретную платформу в соответствии с описанием модели и конкретной 3D сценой • Записывает в низкоуровневом формате, «заточенном» под 3D сцену и платформу • Игра работает с семейством низкоуровневых форматов • Это происходит автоматически и прозрачно для игрового кода и разработчиков

  47. Case 2: настройка контента • Художник создает модель и указывает ее рабочие характеристики • Игровой код активно использует данные, специфичные для данной модели (мы предполагаем доступ к настройкам «только для чтения») • Требования • Гарантии корректности данных • Эффективный и удобный доступ к данным • Автоматическая обратная совместимость

  48. Настройка: о чем речь? • В идеале, художник прямо в пакете моделирования указывает параметры:

  49. Настройка: о чем речь? (2) • Для отладки и тестирования настройки могут быть вынесены в текстовые файлы • Как XML: <Component name="GunControl" template="PLANE_GUN"> <Attr name="AmmoModel" value="Bullets/ammo"/> <Attr name="MinDistance" value="4.5"/> <Attr name="MaxDistance" value="1000.0"/> <Attr name="FullAmmoPack" value="400"/> </Component> • Или как любой другой удобный формат: GunControl:PLANE_GUN { AmmoModel = "Bullets/ammo" MinDistance = 4.5 MaxDistance = 1000.0 FullAmmoPack = 400 }

  50. Настройка: о чем речь? (3) • Впрочем, стандартный инструмент удобнее:

More Related