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

Содержание

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

Слайд 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Характеристики системы разработки игр
Простота внедрения
Гибкость и расширяемость
Масштабируемость
Производительность


Слайд 11Задачи: простота внедрения
Быстрое обучение
Простые, но мощные средства
Единообразные инструменты
Автоматизация рутинных процессов
Продвинутые средства

отладки контента

Слайд 12Задачи: гибкость, расширяемость
Простота настройки контента
Изменение данных «в последний момент»
Внедрение новых технологий

в сжатые сроки
Быстрая проверка идей без цикла разработки/внедрения

Слайд 13Задачи: масштабируемость
Большие и сверхбольшие размеры контента
Параллельное создание контента
Параллельная разработка нескольких игр
Поддержка

нескольких платформ
Поддержка нескольких жанров

Слайд 14Задачи: производительность технологической цепочки
Четкое разграничение проблем
Разделение труда
Принцип «наиболее квалифицированного специалиста»
Уменьшение «зацепок»

и простоев
Сбалансированное распределение ответственности
Сокращение цикла разработки


Слайд 15Задачи: производительность движка
Еще раз: большие и сверхбольшие размеры контента
Еще раз: сложный

мир, живущий сам по себе
Мощные средства оптимизации контента
Предсказуемое время отклика движка
Быстрая фоновая загрузка контента

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

уровня косвенности решает большинство проблем»



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

будущих расширений

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

база
Композиция компонент – комбинаторный взрыв возможностей

Слайд 19Data driven архитектуры
Инкапсуляция структуры игрового мира и настроек его компонентов
Основное время

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


Слайд 20Data driven архитектуры (2)
Данными легче управлять, чем кодом
У данных меньше «зацепление», чем

у кода
Схема: объект = шаблон + настройки
Жестче схема – меньше ошибок
Данные легче поддаются автоматической обработке: сборке ресурсов, переносу на другие платформы

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

атрибутов и структурная композиция – комбинаторный взрыв возможностей

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

цикл идея-проверка-внедрение

Слайд 23Скрипты (2)
Высокоуровневые примитивы языка, специфичные для игровых задач
Естественный доступ к функциональности

движка
Виртуальная машина, компактное представление, JIT-компиляция
Перенос на другие платформы

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

и прозрачность
Некоторые гарантии целостности


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

мира и их атрибутам
Но…

Слайд 26Пиррова победа?
Чрезмерная общность
Высокие издержки, «over engineering»
Неформальные «договоренности»
Явные спецификации недостаточно формализованы или

отсутствуют
Связи кода со внутренней структурой 3D моделей и сцен
Что и как часто мы будем изменять или использовать
Естественные последствия требований гибкости и расширяемости


Слайд 27Пиррова победа? (2)
Еще раз: большой и сложный мир…
Высокая степень детализации контента
Какова

цена единообразного подхода к атрибутам системы?
«Грубый помол»?
Масштабируемость тех. цепочки?
Масштабируемость движка?
Какова цена неформальных договоренностей?
Целостность ресурсов?
Масштабируемость тех. цепочки?
Производительность движка?

Слайд 28Два детальных примера
Хранение 3D сцен на диске и их представление в

памяти
Настройка контента и доступ к параметрам игровых объектов из игры


Слайд 29Case 1: представление 3D моделей
Типичные схемы:
Монолитное представление
Слишком жесткое, но эффективное
Открытое (компонентное)

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


Слайд 303D: монолитное представление
«Классика жанра»: Quake
При разработке движка фиксируется набор управляемых атрибутов

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


Слайд 313D: открытое представление
Scene graph, DAG, дерево подобъектов
Доступны все атрибуты всех объектов

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


Слайд 323D: открытое представление (2)
Существуют правила именования подобъектов и их атрибутов
Чаще всего,

неявные правила («изустное творчество»), поскольку игровой код отделен от инструментов по созданию контента
Неявные правила – неформальные договоренности

Слайд 333D: открытое представление (3)
«Слишком» гибкое представление
Наши намерения не выражены явно
Весь спектр

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


Слайд 343D: открытое представление (4)
Статические объекты могут быть представлены более эффективно
Но оптимизатор

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


Слайд 353D: открытое представление (5)
Игровой код: уродлив, неэффективен, подвержен ошибкам
// получение бокса

левого закрылка
render::node n =
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();

Заранее известно, что левый закрылок должен присутствовать в модели
Известно, что нужен только бокс закрылка



Слайд 363D: открытое представление (6)
Игровой код: хотелось бы что-то подобное:

// получение бокса

левого закрылка
render::box b =
Plane.FlapsLeft.box;

Более красиво, более эффективно
Целостность данных должна проверяться раньше, не во время исполнения


Слайд 37Вседозволенность против гибкости
Абстрагирование и позднее связывание вызывают потери неявной информации о

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


Слайд 38Вседозволенность: Стек на 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

Слайд 39Гибкость: Стек на C# с Generics
class Stack
{
public void Push( T

item );
public T Pop();
}
Stack s = new Stack();
s.Push( 123 );
int n = s.Pop();

«Заточенность»: стек int – ровно то, что нужно
Эффективность: нет преобразований
Целостность: ошибки типов диагностируются во время компиляции


Слайд 403D: явная параметризация
Явная параметризация типов в языках программирования переносит время связывания

на момент компиляции и дает:
Эффективность
Удобство
Гарантии целостности
При этом сохраняя гибкость и расширяемость


Слайд 413D: открытое представление (7)
// получение бокса левого закрылка
render::box b =

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


Слайд 423D: явная параметризация (2)
Введем в движок описание 3D моделей:
game FighterAce
{
scene

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


Слайд 433D: явная параметризация (3)
Для архитектур, управляемых данными, – это естественный шаг
Требования

к модели используются при экспорте, оптимизации и сборке ресурсов
Информация о связях игрового кода с 3D моделью используется для формирования эффективного memory layout и удобного интерфейса к объекту

Слайд 443D: назад к монолитам
Фактически, мы возвращаемся к «жестким» монолитным форматам хранения

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

Слайд 453D: memory layout
В соответствии с описанием 3D модели, все ее атрибуты

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

Слайд 463D: детали
Автоматически генерируемый для игровых объектов интерфейс работы с 3D моделью

(общая идея):
class Plane : public render::u_object
{
public:
struct FlapsLeft_t { render::box8 box; };

enum instance_t { LaGG3, P38L } instance;
FlapsLeft_t FlapsLeft;

static Plane* Load( instance_t inst );
Plane* Copy() const;
void Destroy();
};


Слайд 473D: детали (2)
Формат представления конкретной модели определяется файлом описания и собственно

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

Слайд 483D: детали (3)
Движок (включая рендер) работает со структурой, близкой к scene

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

Слайд 493D: голые факты
Считаем только пользовательскую часть, без звуков и 3D ресурсов
Не

самый худший случай
Один самолет B-17 (без панели кабины)
Около 50 подобъектов, анимированных художниками
Около 100 атрибутов, изменяемых из игры (преимущественно матрицы трансформации, флаги видимости, контроллеры анимаций)



Слайд 503D: голые факты
Вседозволенность:
Одна копия: около 80K в 140 блоках
Разделяемые данные: около

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



Слайд 51Case 1: результаты
Высокая производительность
Минимальные требования к ресурсам
Отсутствие сложного lifetime management
Эффективная работа

с памятью
Полностью автоматическая сборка
100% гарантии целостности ресурсов
Ясный, простой и эффективный игровой код
Сохранены гибкость и расширяемость

Слайд 52Case 1: заключение
Обобщенный формат используется для хранения и трансформаций контента
Сборщик ресурсов


Выполняет низкоуровневую оптимизацию под конкретную платформу в соответствии с описанием модели и конкретной 3D сценой
Записывает в низкоуровневом формате, «заточенном» под 3D сцену и платформу
Игра работает с семейством низкоуровневых форматов
Это происходит автоматически и прозрачно для игрового кода и разработчиков

Слайд 53Case 2: настройка контента
Художник создает модель и указывает ее рабочие характеристики
Игровой

код активно использует данные, специфичные для данной модели (мы предполагаем доступ к настройкам «только для чтения»)
Требования
Гарантии корректности данных
Эффективный и удобный доступ к данным
Автоматическая обратная совместимость


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

параметры:

Слайд 55Настройка: о чем речь? (2)
Для отладки и тестирования настройки могут быть

вынесены в текстовые файлы
Как XML:






Или как любой другой удобный формат:
GunControl : PLANE_GUN
{
AmmoModel = "Bullets/ammo"
MinDistance = 4.5
MaxDistance = 1000.0
FullAmmoPack = 400
}


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


Слайд 57Настройка: о чем речь? (3)
Игровому коду эта информация должна быть доступна

естественными (языковыми) средствами:

Слайд 58Настройка: типичные схемы
Пары «имя» – «значение»
Предельная гибкость, хрупкость и неэффективность
Громоздкий код
Сериализация/десериализация
Ясный

и надежный код
Гарантии целостности
Потенциально – гибкость, расширяемость и эффективность

Слайд 59Настройка: сериализация
Сериализация/десериализация
Описание библиотек типов
Инструменты для редактирования
Сборщик, выполняющий проверку валидности входных данных

и сериализацию в финальный формат
Если в системе разработки есть такие возможности, это уже хорошо!

Слайд 60Настройка: подводные камни
Обратная совместимость и расширяемость схемы
Эффективное представление в runtime
Быстрая загрузка
Минимальный

расход памяти



Слайд 61Настройка: обратная совместимость
Следует отличать «значения по умолчанию» от введенных значений
Это позволит

изменить значения по умолчанию сразу для большого класса объектов
Экземпляр = шаблон + переопределенные значения
Готовность к расширению схемы


Слайд 62Настройка: применение шаблонов
Явное описание структуры компонента
Указываются типы и значения по умолчанию
Не

имеющие умолчаний поля являются обязательными






Слайд 63Настройка: применение шаблонов (2)
Конкретный экземпляр компонента «наследуется» от шаблона и переопределяет

значения полей
Обязательны значения обязательных полей
Нельзя вводить новые поля
Нельзя указывать тип полей







Слайд 64Настройка: применение шаблонов (3)
Можно использовать промежуточные шаблоны (единица крупных замен значений

по умолчанию)
Промежуточные шаблоны «наследуются» от других шаблонов и переопределяют значения полей
Нельзя вводить новые поля
Нельзя указывать тип полей


Слайд 65Настройка: библиотека типов
Чтение всех «корневых» шаблонов (их изменение, как правило, производит

игровой программист)
Генерация библиотек типов для внешних (управляемых данными) инструментов
Генерация C++ описаний компонентов для эффективной работы в runtime конкретной платформы


Слайд 66Настройка: библиотека типов (2)
Пример сгенерированного C++ объявления:

struct PLANE_GUN
{
render::obj_ref AmmoModel;

float MinDistance;
float MaxDistance;
int FullAmmoPack;

sdf::t_carray g_Other;
};



Слайд 67Настройка: редактирование
Расширяемый набор управляющих элементов для платформы разработчика (PC, Win32)
Стандартные механизмы

библиотеки типов и сериализации/десериализации
Возможность создавать промежуточные шаблоны
Явная визуальная дифференциация значений по умолчанию и явно заданных значений
Работа с больших количеством промежуточных форматов (XML, обобщенные форматы хранения 3D сцен, etc)

Слайд 68Настройка: сборщик
Читает все шаблоны и компоненты из промежуточных форматов и библиотек

типов
Диагностирует разночтения библиотеки типов и «корневых» шаблонов
Формирует полные (плоские) компоненты
Диагностирует отсутствующие обязательные поля или поля, отсутствующие в схеме
При необходимости, формирует дополнительные массивы пар «имя» – «значение»

Слайд 69Настройка: сборщик (2)
Сериализует данные в финальный, зависящий от target платформы, формат
Оптимизирует

размещение (данные «только для чтения»)
Исключает дубликаты
Формирует плоское представление сложных типов (строк, массивов, ресурсных указателей)
В финальном формате данные на диске хранятся в готовом к употреблению виде
Выделение непрерывной области памяти, чтение с диска, fix up, использование

Слайд 70Настройка: детали
Для плоского и относительно-адресуемого представления сложных типов используются те же

типы, что и в 3D сценах

template
struct t_carray
{
// Интерфейс как у константного std::vector
const T* begin() const
{ return ShiftPointer(this, iBegin); }
// ...

private:
std::ptrdiff_t iBegin, iEnd;
};


Слайд 71Настройка: детали (2)
Результирующий (автоматически сгенерированный и библиотечный) код непереносим, а финальные

бинарные форматы «заточены» под конкретную пару компилятор-платформа
Для другой пары компилятор-платформа будет сгенерирован другой код и построены другие форматы
Может быть изменен порядок байт и выполнено строгое выравнивание
Все это произойдет автоматически


Слайд 72Case 2: результаты
Высокая производительность
Минимальные требования к ресурсам
Эффективная работа с памятью
Полностью автоматическая

сборка
100% гарантии целостности ресурсов
Ясный, простой и эффективный игровой код
Сохранены гибкость и расширяемость


Слайд 73Case 2: заключение
Обобщенные форматы (XML…) используются для хранения и редактирования контента
Сборщик

ресурсов
Выполняет низкоуровневую оптимизацию под конкретную платформу в соответствии с описанием «корневых» шаблонов
Записывает в низкоуровневом формате, «заточенном» под платформу и компилятор
Игра работает с семейством низкоуровневых форматов
Это происходит автоматически и прозрачно для игрового кода и разработчиков

Слайд 74Заключение
Мы рассмотрели приемы сохранения гибкости и расширяемости системы в условиях ограниченных

ресурсов без потери производительности и масштабируемости
В двух приведенных примерах это достигалось явной демонстрацией намерений со стороны разработчика, что позволяло перенести время связывания с runtime на более ранние моменты
Благодаря этим приемам мы получали 100% гарантии целостности ресурсов

Слайд 75Дальнейшие шаги
Без сомнения, подобный подход может быть применен ко многим аспектам

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




Слайд 76Вопросы?
mailto:ruslan@vr1.spb.ru
http://aruslan.nm.ru
Мой e-mail и домашняя страничка
http://www.jaleco.com
Компания, в которой я работаю
http://www.gamedev.ru
http://www.gamasutra.com


Обратная связь

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

Email: Нажмите что бы посмотреть 

Что такое ThePresentation.ru?

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


Для правообладателей

Яндекс.Метрика