Как движку нравятся исходные объекты?

9

На движке Source (и это его предшественник, goldsrc, quake) игровые объекты делятся на два типа: мир и сущности. Мир - это геометрия карты, а сущности - это игроки, частицы, звуки, очки и т. Д. (Для движка Source).

Каждая сущность имеет функцию мышления , которая выполняет всю логику для этой сущности.

Таким образом, если все, что необходимо обработать, происходит из базового класса с функцией Think, игровой движок может хранить все в списке и в каждом кадре циклически проходить по нему и вызывать эту функцию.

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

Итак, как движок вроде Source заботится (обрабатывает, обновляет, рисует и т. Д.) Игровых объектов?

JulioC
источник
2
Почему это важно, как <some commercial engine>это?
Коммунистическая утка
8
@ Коммунистическая утка, я думаю, что реальный вопрос здесь заключается в том, насколько успешный двигатель делает это, чтобы я мог учиться у них?
SUBB

Ответы:

5

В общем, другого способа сделать это практически нет - вам придется проходить циклы и вызывать think()каждую сущность хотя бы раз в несколько кадров.

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

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

Вот почему механизм Source устанавливает жесткое ограничение на количество сущностей, которые могут существовать одновременно : 4096 сущностей, из которых только половина (2048) может быть объединена в сеть. Пройдите любой из этих ограничений, и игра вылетит.

Вот почему при создании карты рекомендуется не использовать более 800 объектов.

BlueRaja - Дэнни Пфлугхофт
источник
Разве вызовы функций 2 ^ 12 не являются БОЛЬШИМ номером для каждого кадра?
JulioC
@ Júlio: Ну, при 60 кадрах в секунду это 246 тыс. Вызовов функций в секунду - это много, но определенно выполнимо на современном оборудовании. Помните, однако, что это абсолютный максимум, допустимый до сбоя движка Source - обычно на карте гораздо меньше объектов.
BlueRaja - Дэнни Пфлугхофт
5
У объектов есть время на следующее размышление, функция Think не вызывается для каждого кадра и не для всех объектов. Я помню, что для Quake 2 минимальное время обдумывания было 0,1 (100 мсек), только 10 кадров в секунду для обработки объектов.
bcsanches
«Вы можете поместить сущности в свой собственный поток, но тогда у вас будет целый кошмар синхронизации состояний, который определенно не стоит». Посмотрите эти слайды Killzone 4, если считаете, что это того не стоит: de.slideshare.net/jrouwe/…
Тара
3

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

for each object
    do physics
    do game logic
    draw

становится

call physics subsystem
call game logic subsystem
call drawing subsystem

Физический двигатель заботится о позициях и размерах.

Game Logic Engine заботится о том, чтобы интерпретировать, что физический движок изменился (он может помешать некоторым путевым точкам ...), какие цели преследуют персонажи и какое поведение они должны выполнять , он запускает запланированные сценарии (эта функция мышления ).

Drawing Engine рисует, какие объекты видимы, и он знает, какие объекты видимы, потому что движки Quake обманывают здесь (см. Раздел Draw).

Мой вам совет - лучше изучить, как выполняются симуляции, а не игровые движки. Существует огромная поп-культура, связанная с разработкой игр, и игровые движки сделаны на императивных языках (из-за традиций и скорости); так что мне было более поучительно получать хорошие учебники (скорее теорию) и ТОГДА смотреть на движки (практика), а не смотреть на движки и ломать голову часами, как они это делали.

физика

Целостное представление об итерациях всех сущностей и их выполнении может привести к проблемам. Будут конфликты и тд. Я верю, что у Valve есть Havok, и я думаю, что Havok заботится о достаточно правильной физике.

Считать

Функция Think запускается, когда время в игре равно времени в следующем разуме . Так работает в движке Quake, а движок Quake является основой для двигателей Half Life. Это НЕ запускается каждый раз.

Внутренне это должна быть простая итерация по списку объектов и проверка, прошло ли время для вызова функции Think. Временная сложность будет O (N), где N - количество объектов.

Если существует очень большое количество объектов, вы должны измерить, насколько это улучшит fps. Обратите внимание, что по закону Амдала это потенциально невидимое ускорение. Я имею в виду, вы просто перебираете все элементы, уменьшаете и проверяете одно число.

Я бы ускорил его, отсортировав сущности по nextthink (создайте список указателей на сущности и сортируйте их каждый раз; не массив сущностей, потому что сущности могут изменить их nextthink в любое время, поэтому для их реорганизации в массиве требуется O (N) вместо O ( 1) в списке).

Вы также должны посмотреть на O (1) планировщик в Linux .

Рисовать

Двигатель рисует то, что приблизительно видно из области, в которой находится камера. Уровень игры - это разбиение на дерево, а область - это лист этого дерева. Я не буду беспокоить Вас подробностями об этом ... Так что, если сущность видима, она помещается в набор видимых сущностей, и они рисуются.

Они хранят, какие области являются потенциально видимыми областями. Это называется «потенциально видимый набор», сокращенно PVS . Есть визуализация PVS , зеленая капсула игрока и вокруг него отображается то, что содержит его PVS.

user712092
источник
2

Таким образом, если все, что нужно обработать, происходит из базового класса с функцией Think, игровой движок может хранить все в списке и в каждом кадре циклически проходить по нему и вызывать эту функцию.

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

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

Вам не обязательно даже выводить все из общего базового класса в этот момент; Источник идет слишком долго с наследованием злоупотребления для того, что в противном случае может быть реализовано в качестве данных в этом отношении.

Конечно, у вас всегда будет верхний предел количества объектов, которые вы можете обработать на кадр, даже если вы начнете перекладывать работу на другие ядра. Обойти это невозможно, вам просто нужно иметь представление о том, что это за предел в вашей реализации, и предпринимать шаги по его устранению (надлежащая выборка этапов обработки для объектов, которые в них не нуждаются, избегая чрезмерной гранулярности в объектах и ​​т. Д. так далее).

BlueRaja - Дэнни Пфлугхофт
источник
1

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

Просматривая ссылку, которую вы разместили на движке исходного кода, вы также можете прочитать, что вы можете настроить время мышления и разные контексты мышления для каждой из ваших сущностей, помимо очевидного жесткого ограничения, на которое уже указывал кто-то, это будет ключом к достижению большей производительности. с большим числом объектов, либо путем создания пошаговых обновлений, которые распространяют ресурсоемкую обработку через несколько кадров выполнения, либо путем исключения ненужной обработки в зависимости от текущего контекста (т.е. объекты, которые находятся слишком далеко или за пределами восприятия игрока, не нуждаются тот же уровень «детализации мысли», что и у персонажей, которые находятся рядом с игроком, просто не увидит персонажа, находящегося в 2 милях от него, ковыряющегося в носу).

Есть и другие, более специфические уровни оптимизации, в зависимости от конкретной игровой логики и ситуации.

Серхио Франко
источник
"игрок просто не увидит, как персонаж в двух милях отсюда ковыряется в носу" Ха-ха! Но почему никто не указывает на то, что использование виртуальных функций очень медленное?
Тара