Быстрое обнаружение столкновений 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.


Мне интересно, как ты получил это, чтобы перейти на 90K в первую очередь. мои дроссели в 20K (я делаю полное обнаружение SAT MTV все же). Но я перебираю всех врагов - единственное, что кажется возможным. Тем не менее, вам нужно проверить, проверены ли они уже, потому что если вы делаете то, что говорите, то каждый проходит тестирование со всеми дважды.
Бредовая логика


На вопрос, который связал @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) у вас гораздо более сбалансированное дерево, меньше накладных расходов ,


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

0

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


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

0

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.