Паттерны программирования игр
— Паттерны оптимизации
353
for (int i = 0; i < numEntities; i++)
{
entities[i]->ai()->update();
}
// 73 '
for (int i = 0; i < numEntities; i++)
{
entities[i]->physics()->update();
}
// 8
for (int i = 0; i < numEntities; i++)
{
entities[i]->render()->render();
}
// 7 $ 6…
}
До знакомства с кэшем процессора код в примере
выглядел весьма безобидно. Но теперь-то вы догадыва-
етесь, что не все так просто. Данный код не просто ло-
мает кэш, он заходит со спины и избивает до полусмер-
ти. Смотрите.
• В массиве игровых сущностей хранятся
указате-
ли
на них, то есть для доступа к каждому элемен-
ту массива нам приходится проходить по указате-
лю. Это промах кэша.
• Затем в каждой сущности находится указатель
на компонент. Еще один промах кэша.
• Затем мы обновляем компонент.
• Начинаем с первого шага для
каждого компонента
каждой сущности в игре
.
Самое страшное: мы понятия не имеем о расположе-
нии данных в памяти. Мы полностью в распоряжении
менеджера памяти. А поскольку сущности создаются
по ходу и память из-под них также освобождается, куча,
скорее всего, становится организованной абсолютно
случайным образом.
354
Локальность данных (Data Locality) —
Паттерны программирования игр
Рис. 17.4.
Каждый кадр игре приходится переходить по всем
стрелкам, чтобы получить необходимые данные
Если ваша цель — безумный тур по пространству игро-
вых адресов памяти «256 Мб оперативной памяти за четы-
ре ночи!», то все просто замечательно. Но, к сожалению,
наша цель — заставить игру работать быстро, а беспоря-
дочное перемещение по всей памяти
не
лучший способ
это сделать. Помните функцию
sleepFor500Cycles()
?
Данный код вызывает ее
все время
.
Мы следуем к сущности по указателю
только затем,
чтобы немедленно перейти по
другому
указателю к ком-
поненту. Сама по себе
GameEntity
не содержит инте-
ресных состояний или полезных методов. Игровому ци-
клу нужны
компоненты
.
От огромных созвездий игровых сущностей и компо-
нентов, раскиданных по адресному пространству, слов-
но по темному небу, вернемся на Землю. Создадим боль-
шой массив для каждого типа компонента: одномерный
массив компонентов ИИ, такой же для физики и еще
один для рендеринга.
AIComponent* aiComponents =
new AIComponent[MAX_ENTITIES];
Термин для обозначе-
ния перехода по указа-
телям — «гонка указате-
лей» (pointer chasing).
На самом деле это даже
близко не так весело,
как звучит.
Больше всего в исполь-
зовании компонентов
я не люблю то, что
слово «Component» та-
кое длинное.
Do'stlaringiz bilan baham: |