Ускорение алгоритма поиска пересечений в игре

У меня есть 2D игра, в которой есть игроки и противники. Каждый может стрелять множеством пуль. На данный момент для проверки пересечений Entity (это любой рисуемый объект: игрок, враг, пуля) проверяется пересечение каждого с каждым. События пересечения обрабатываются по-разному (игрок+пуля=-хп, пуля+пуля=-пули и так далее). В итоге игра начинает лагать, когда на экране много врагов и у игрока баф на количество пуль. Какие алгоритмы можно применить для более быстрой проверки пересечений?

Игрок: мало - 1 или 2; враги: много, но не больше пары десятков; пули: очень много, но не больше тысячи, есть разные типы пуль.

Игра написана на C++. Проверено, что замедляет программу именно это место.


Ответы (2 шт):

Автор решения: AivanF.

К сожалению, Вы не предоставили информации ни по архитектуре игры, ни по её жанру, поэтому придётся предполагать :) Жанр скорее всего Top-Down Shooter, архитектура, судя по комментариям, примерно следующая:

Предположительная архитектура, набросок UML диаграммы классов

Один из вариантов оптимизации стрельбы – реализовать её как отдельную игровую сущность, а не как разновидность обычных объектов с полноценной физикой:

Улучшенная архитектура, набросок UML диаграммы классов

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

Если же Ваши пули, снаряды летят с относительно небольшой скоростью, то их проверку столкновений с юнитами всё равно можно проводить раз в N шагов. А если снаряд летит по воздуху (например, выстрел гранатомёта) то расчёты достаточно проводить всего дважды – в момент выстрела построить траекторию с учётом статических объектов, и в момент падения проверять столкновения с юнитами для нанесения урона.

Также в комментариях упоминали про разделение игрового поля на части и их независимую обработку. Этот приём называется зонирование (zoning) и довольно часто применяется в ГеймДеве будучи полезным и важным как для дизайнеров, так и для разработчиков, т.к позволяет значительно оптимизировать и игровую физику, и графический рендер – например, это актуально для сцен с качественными зеркальными эффектами, т.к это очень ресурсозатратный процесс, особенно в старых играх. И в целом, в истории игровой индустрии полно примеров компромиссов дизайнеров и разработчиков, важно смотреть сразу с обеих сторон.


Ещё несколько советов:

  1. В вопросе по оптимизации кода старайтесь приводить или сам код, алгоритмы, или архитектуру, например, используя UML диаграммы классов, хотя бы в урезанном виде, как выше сделал я.
  2. В вопросах по ГеймДеву стоит описывать жанр и желаемое поведение, т.к нередко его можно достичь совсем другими способами. Впрочем, это касается не только гейм.дева.
  3. Учите английский и не брезгайте пользоваться, искать ответы в более тематических сайтах, например, на GameDev StackExchange.
→ Ссылка
Автор решения: Дима Савичев

Самое простое что можно предложить это реализовать пулю как луч ( если конечно у вас пули не меняют направление в зависимости от ситуаций, тогда можно предоставить пулю как сущность с своим BBox и уже проверять пересечение с ним ), а все объекты поместить в октарное дерево и соотвественно проверять через него пересечение луча ( или BBox пули ) и дерева, таким образом вы отсечете ненужные проверки, так же как уже упоминалось в ответе выше стоит разделить на зоны, чтобы избежать 100% ненужных проверок

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

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

→ Ссылка