Быстрое обнаружение столкновений 2D

13

Недавно я работал над быстро развивающимся 2d шутером и столкнулся с серьезной проблемой. Обнаружение столкновения. Конечно, это работает, но это очень медленно. Моя цель: иметь много врагов на экране, чтобы они не касались друг друга. Все враги преследуют игрока. Большинство из них имеют одинаковую скорость, поэтому рано или поздно все они занимают одно и то же место, преследуя игрока. Это действительно снижает веселье, поскольку для игрока похоже, что вас преследует только один враг. Чтобы они не занимали одно и то же место, я добавил обнаружение столкновений (очень простое двумерное обнаружение, единственный известный мне метод).

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

Это отлично работает. Пока у меня есть <200 вражеских сущностей. Когда я приближаюсь к 300-350 вражеским объектам, моя частота кадров начинает сильно падать. Сначала я подумал, что это плохой рендеринг, поэтому я убрал их колл. Это не помогло, поэтому я, конечно, понял, что это метод обновления. Единственная тяжелая часть в их методе обновления - это каждая часть врага, проходящая через каждого врага. Когда я приближаюсь к 300 врагам, игра делает шаг 90000 (300x300). Мой мой ~

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

Т.Л., др? Как мне достичь обнаружения столкновений между множеством объектов?

Быстрое редактирование: если вам нужна помощь, я использую C # XNA.

eShredder
источник
Мне интересно, как ты получил это, чтобы перейти на 90K в первую очередь. мои дроссели в 20K (я делаю полное обнаружение SAT MTV все же). Но я перебираю всех врагов - единственное, что кажется возможным. Тем не менее, вам нужно проверить, проверены ли они уже, потому что если вы делаете то, что говорите, то каждый проходит тестирование со всеми дважды.
Бредовая логика
3
Это возможный дубликат gamedev.stackexchange.com/questions/39931/…
Маркус фон Броади
На вопрос, который связал @MarkusvonBroady, есть очень хороший ответ.
Cypher

Ответы:

11

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

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

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

Следующий список - это те, которые находятся в буферном диапазоне, который мог бы переместиться в диапазон объекта без особых усилий. Мы будем называть этот диапазон X * 1,5 только для аргументации. Это временный список, в котором вы будете обновлять лишь несколько из них за кадр, но при этом убедитесь, что вы просматриваете их достаточно быстро, чтобы сохранить видимость работы.

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

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

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

Надеюсь это поможет.

Джеймс
источник
1
Это расплывчатый ответ. И можем ли мы принять пропущенные столкновения ?? Гораздо проще, используйте структуру данных, которая сделает для вас поверхностное разбиение, например, Quad Tree, о котором я говорю здесь. Даже Quad Tree нужно немного доработать, чтобы избежать накладных расходов, поэтому я не могу себе представить сложность «решения», о котором вы говорите. Основное правило программирования: просто используйте правильную структуру данных.
GameAlchemist
@VincentPiel Граф сцены не сложнее, чем квад-дерево.
Cypher
@James: очевидно, это сложнее. Если вы не возражаете против использования полной скорости QuadTree, вы можете получить библиотеку QuadTree в сети и заставить ее работать идеально за пару часов. Не вопрос, как: что я помещаю в первый список, второй, третий, как я решаю поместить объект в другой список ... и никакое столкновение не пропущено. Зачем использовать велосипед, если у вас есть машина?
GameAlchemist
@ VincentPiel Я думаю, что вы хотели @ ваш комментарий Сайфер вместо меня здесь. В любом случае, квад-дерево - это просто тип графа сцены, и вы должны помнить, что вы работаете со скоростью X кадров в секунду. Если вы замечаете пропущенные столкновения, вам нужно отрегулировать пороговые значения диапазона, чтобы лучше сбалансировать ситуацию. Мое решение - просто очень простой подход - убедиться, что вы проверяете вещи в каждом кадре, с которыми есть вероятность столкновения, и затем выполняете фоновые / ограниченные обновления для остальных, чтобы увидеть, имеют ли они право на более высокий приоритет.
Джеймс
6

Вы должны обрабатывать столкновения с отсортированной структурой данных, так что вы можете иметь n * log (n) раз вместо ужасного n ^ 2. И n * log (n) почти линейный, как вы, возможно, знаете. Один (классический) пример - quadtree, здесь есть довольно простое и хорошо написанное руководство с графикой и кодом (Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: довольно легко найти реализацию QuadTrees на любом языке. Тем не менее, вам нужно подумать о правильной «гранулярности» для дерева, и чем больше размер дерева, тем больше у нас объектов, которые не помещаются внутри узла. Rq3: Как только у вас есть дерево, «столкновение» между экраном и сущностями дает вам ... видимые сущности !! во время, больше похожее на log (n), так почему бы и нет, если n большое? (наихудший случай - это, очевидно, время n для этого подхода.)
Rq 2: так как ваше пространственное разделение сделано только для обнаружения столкновений, у вас есть полная свобода делить пространство по своему усмотрению. Например, я бы не делил на четыре части эгала, а скорее использовал бы барицентр сущностей текущего уровня в качестве центра для нового разрыва. 1) алгоритм по-прежнему n * log (n), 2) вы теряете возможность «перестроить» сцену из дерева - но вам все равно - и 3) у вас гораздо более сбалансированное дерево, меньше накладных расходов ,

GameAlchemist
источник
Да, квад-дерево - это просто тип графа сцены. Я просто всегда предполагаю, что люди, которые здесь находятся, хотят сами что-то написать, а не использовать чужую библиотеку, в этом случае зачем останавливаться на квад-дереве, просто найти полную библиотеку столкновений.
Джеймс
0

дерево разделов двоичного пространства, quadtree, octree (для 3D) - это возможные деревья, которые вы можете генерировать (или поддерживать, если вы амбициозны) при каждом вызове обновления для каждого объекта, к которому вы хотите применить столкновение.

kchoi
источник
3
Это более уместно, чтобы быть комментарием. Попробуйте добавить больше к своему ответу.
0

Я довольно наивен, когда говорят о четырехугольнике или октавном дереве. Но я думаю, что этот метод должен сделать:

Вам нужно будет изменить структуру / класс игрока. Добавить массив / вектор указателей в структуру другого игрока.

Каждую секунду проверяйте расстояние между каждыми двумя игроками. Если он настолько низок, что его можно достичь в течение 1 секунды, добавьте указатель этого игрока к массиву столкновений текущего игрока.

Теперь проверяйте только столкновения между игроками в списке друг друга.

user3042253
источник