2009-05-22 2 views
14

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

У меня есть несколько особых проблем для этого игрового мира ...

  • Я хочу, чтобы иметь возможность быть в состоянии использовать большое количество объектов в игровом мире сразу. Однако,% сущностей не будет сталкиваться с объектами того же типа. Например, снаряды не будут сталкиваться с другими снарядами.

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

  • В игровом мире очень мало статических или не движущихся объектов.

Я заинтересован в использовании нечто подобное тому, что описано в ответе здесь: Quadtree vs Red-Black tree for a game in C++?

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

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

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

ответ

2

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

Многие структуры ускорения (например, хороший BSP) могут занять некоторое время, чтобы настроить и, как правило, неприемлемы для быстрой анимации.

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

6

Если бы я был вами, я бы начал с реализации простого дерева BSP (двоичного пространства). Так как вы работаете в 2D, проверка привязки коробки очень быстро.Вы в основном нужны три класса: CBspTree, CBspNode и CBspCut (на самом деле не нужен)

  1. CBspTree один экземпляр корневого узла класса CBspNode
  2. CBspNode имеет экземпляр CBspCut
  3. CBspCut символизируют, как вы режете набор в двух непересекающихся множествах. Это может быть эффективно решено путем введения полиморфизма (например, CBspCutX или CBspCutY или какой-либо другой линии резания). CBspCut также имеет два CBspNode

интерфейс к поделенному миру будет через класс дерева, и это может быть очень хорошая идея, чтобы создать еще один слой поверх, что, в случае, если вы хотели бы заменить БСП решение, например квадратное дерево. Как только вы получите это. Но, по моему опыту, BSP будет прекрасно.

Существуют различные стратегии хранения ваших предметов в дереве. Я имею в виду, что вы можете выбрать, например, какой-то контейнер в каждом узле, который содержит ссылки на объекты, занимающие эту область. Это означает, что (как вы сами спрашиваете себя), что крупные предметы будут занимать много листьев, т. Е. Будет много ссылок на большие объекты, а очень мелкие предметы появятся на отдельных листьях.

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

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

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

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

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

Этого можно избежать, введя какую-то ленивую систему слияния и сплит-системы, т. Е. У вас есть какая-то грязная отметка или изменение количества. Выгружайте все операции, которые могут быть загружены, т. Е. Перемещение 10 объектов, а вставка 5 может быть одной партией.Как только эта партия операций будет завершена, вы проверите, загрязнено ли дерево, и затем выполните необходимые операции слияния и/или разделения.

Опубликуйте несколько комментариев, если вы хотите, чтобы я объяснил дальше.

Cheers!


Редактировать

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

4

Меня беспокоит то, насколько хорошо будет дерево подразделение мира иметь возможность обрабатывать большие различия в размерах в лицах ? Чтобы разделить мир вверх достаточно для небольших объектов более крупным нужно будет занять большое количество регионов, и я обеспокоен тем, как это повлияет на производительность системы .

Использование квадратного дерева. Для объектов, которые существуют в нескольких областях, у вас есть несколько вариантов:

  • Сохраните объект в обеих ветвях, до конца. Все заканчивается в листовых узлах, но вы можете получить значительное количество дополнительных указателей. Может быть уместным для статических вещей.

  • Разделите объект на границе зоны и вставьте каждую деталь в соответствующие местоположения. Создает много боли и не очень хорошо определен для большого количества объектов.

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

Кстати, причина, по которой вы используете квадроцикл, состоит в том, что с ней действительно очень легко работать. У вас нет эвристического создания, как вы могли бы с некоторыми реализациями BSP. Это просто, и он выполняет свою работу.

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

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

Очевидно, что в зависимости от количества объектов, размера игрового мира и т. Д. Компромисс может не стоить того. Обычно это победа, но ее трудно понять, не делая этого.

1

У меня возникнет соблазн просто наложить грубую сетку поверх игровой зоны, чтобы сформировать 2D-хэш. Если сетка, по крайней мере, имеет размер самой большой сущности, тогда у вас будет только 9 квадратов сетки для проверки на наличие столкновений, и это намного проще, чем управление четырьмя деревьями или произвольными деревьями BSP. Накладные расходы при определении того, какой грубой квадрат сетки вы находитесь, как правило, всего 2 арифметические операции, и когда обнаружено изменение, сетка просто должна удалить одну ссылку/идентификатор/указатель из одного квадратного списка и добавить то же самое к другому квадрату.

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

Смежные вопросы