Недавно я работал над быстро развивающимся 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.
источник
Ответы:
Вы уже ударили по своей проблеме прямо в голову, вы проходите проверку каждой сущности против любой другой сущности. То, что вам нужно, это какой-то тип системы «Уровень детализации» (это в значительной степени очень простой граф сцены, вы просто используете его для других вещей, кроме рендеринга :)), где возможные кандидаты в коллизии лучше выбираются.
Я обычно делаю три сборника для подобных систем. И когда вы говорите о количестве сущностей, на которые вы рассчитываете, вам, возможно, даже понадобится использовать полный график сцены для этого, поскольку данные отслеживания (3 списка на сущность с записью для каждой другой сущности) могут быстро получить доступ. контроля.
В принципе, у вас есть три списка. Первым должен быть очень маленький список сущностей, которые вы будете проверять с взаимодействиями в каждом кадре. Вы определяете это, потому что они находятся в пределах X диапазона рассматриваемой сущности. Как уже упоминалось, смысл этого списка состоит в том, чтобы содержать каждый объект, который может разумно столкнуться с другим в этом кадре.
Следующий список - это те, которые находятся в буферном диапазоне, который мог бы переместиться в диапазон объекта без особых усилий. Мы будем называть этот диапазон X * 1,5 только для аргументации. Это временный список, в котором вы будете обновлять лишь несколько из них за кадр, но при этом убедитесь, что вы просматриваете их достаточно быстро, чтобы сохранить видимость работы.
Третий список - это список «все остальное», и способ избежать его появления может быть полезен (Сканирование всего списка сущностей и, возможно, проверка его на предмет наличия в одном из других списков, прежде чем переходить, может быть? В зависимости от размеров списка это может сработать, или это может ухудшить ситуацию.) Объекты в этом списке проверяются меньше всего, поскольку для размещения в одном из двух других списков определенно требуется больше, чем несколько кадров.
Что вам также нужно будет сделать, чтобы сохранить это, когда вы выполняете тесты столкновений, убедитесь, что вы обновляете список, в котором находятся сущности. Те, кто выходит за пределы диапазона, должны быть понижены, а аналогичные, которые приближаются, должны быть преобразованы в более активно проверяемый список.
Предполагая, что вы делаете вещи достаточно простыми, это должно соответствовать вашим потребностям. Если вы можете добавить дополнительную информацию к существующему графу сцены рендеринга (при условии, что он у вас есть), вы можете запросить его, чтобы получить список сущностей, которые находятся в разумных пределах в пределах диапазона, который был бы даже лучше, поскольку это целая точка графа сцены. в любом случае (быстрый доступ к списку соответствующих данных на основе позиции). Потенциально для этого потребуется больше работы, и вы всегда должны думать о том, что вам нужно делать, а не о том, что вы должны делать на практике.
Надеюсь это поможет.
источник
Вы должны обрабатывать столкновения с отсортированной структурой данных, так что вы можете иметь 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) у вас гораздо более сбалансированное дерево, меньше накладных расходов ,
источник
дерево разделов двоичного пространства, quadtree, octree (для 3D) - это возможные деревья, которые вы можете генерировать (или поддерживать, если вы амбициозны) при каждом вызове обновления для каждого объекта, к которому вы хотите применить столкновение.
источник
Я довольно наивен, когда говорят о четырехугольнике или октавном дереве. Но я думаю, что этот метод должен сделать:
Вам нужно будет изменить структуру / класс игрока. Добавить массив / вектор указателей в структуру другого игрока.
Каждую секунду проверяйте расстояние между каждыми двумя игроками. Если он настолько низок, что его можно достичь в течение 1 секунды, добавьте указатель этого игрока к массиву столкновений текущего игрока.
Теперь проверяйте только столкновения между игроками в списке друг друга.
источник