На вашем месте я бы начал с реализации простого дерева BSP (двоичного пространственного раздела). Поскольку вы работаете в 2D, проверки связанных полей выполняются очень быстро. В основном вам нужны три класса: CBspTree, CBspNode и CBspCut (на самом деле не нужны)
- CBspTree имеет один экземпляр корневого узла класса CBspNode.
- CBspNode имеет экземпляр CBspCut
- CBspCut символизирует, как вы разрезаете множество на два непересекающихся множества. Это можно легко решить, введя полиморфизм (например, CBspCutX или CBspCutY или какую-либо другую линию разреза). CBspCut также имеет два узла CBspNode.
Интерфейс к разделенному миру будет через класс дерева, и может быть действительно хорошей идеей создать еще один слой поверх него, на случай, если вы захотите заменить решение BSP, например. четырехугольное дерево. Как только вы освоитесь. Но по моему опыту, BSP подойдет.
Существуют разные стратегии хранения предметов в дереве. Я имею в виду, что вы можете выбрать, например. какой-то контейнер в каждом узле, который содержит ссылки на объекты, занимающие эту область. Это означает, однако (как вы спрашиваете себя), что большие элементы будут занимать много листьев, то есть будет много ссылок на большие объекты, а очень маленькие элементы будут отображаться на отдельных листах.
По моему опыту, это не имеет такого большого влияния. Конечно, это важно, но вам нужно провести некоторое тестирование, чтобы проверить, действительно ли это проблема или нет. Вы могли бы обойти это, просто оставив эти элементы в разветвленных узлах дерева, т.е. вы не будете хранить их на «листовом уровне». Это означает, что вы быстро найдете эти объекты, перемещаясь по дереву.
Что касается вашего первого вопроса. Если вы собираетесь использовать это подразделение только для проверки столкновений и больше ничего, я предлагаю никогда не вставлять в дерево вещи, которые никогда не могут столкнуться. Ракета, например, как вы говорите, не может столкнуться с другой ракетой. Это означало бы, что вам даже не нужно хранить ракету в дереве.
Однако вы можете захотеть использовать bsp и для других целей, вы не указали это, но имейте это в виду (для выбора объектов, например, мышью). В противном случае я предлагаю вам сохранить все в bsp и разрешить конфликт позже. Просто попросите bsp списка объектов в определенной области получить ограниченный набор возможных кандидатов на столкновение и после этого выполнить проверку (при условии, что объекты знают, с чем они могут столкнуться, или какой-то другой внешний механизм).
Если вы хотите ускорить работу, вам также необходимо позаботиться об слиянии и разделении, т. е. когда что-то удаляется из дерева, многие узлы становятся пустыми или количество элементов ниже некоторого уровня узла уменьшится ниже некоторого порога слияния. Затем вы хотите объединить два поддерева в один узел, содержащий все элементы. Разделение происходит, когда вы вставляете элементы в мир. Поэтому, когда количество элементов превышает некоторый порог разделения, вы вводите новый разрез, который разделяет мир на две части. Эти пороги слияния и разделения должны быть двумя константами, которые вы можете использовать для настройки эффективности дерева.
Слияние и разделение в основном используются для поддержания баланса дерева и обеспечения того, чтобы оно работало максимально эффективно в соответствии со своими спецификациями. Это действительно то, о чем вам нужно беспокоиться. Перемещение вещей из одного места и, таким образом, обновление дерева — это очень быстро. Но когда дело доходит до слияния и разделения, это может стать дорогостоящим, если вы будете делать это слишком часто.
Этого можно избежать, введя какую-то ленивую систему слияния и разделения, т.е. у вас есть какая-то грязная пометка или счетчик изменений. Объедините в пакеты все операции, которые могут быть объединены в пакеты, т. е. перемещение 10 объектов и вставка 5 могут быть одним пакетом. Как только этот пакет операций завершен, вы проверяете, не загрязнено ли дерево, а затем выполняете необходимые операции слияния и/или разделения.
Оставьте несколько комментариев, если вы хотите, чтобы я объяснил дальше.
Ваше здоровье !
Редактировать
Есть много вещей, которые можно оптимизировать в дереве. Но, как известно, преждевременная оптимизация — корень всех зол. Итак, начните с простого. Например, вы можете создать некую общую систему обратного вызова, которую можно использовать при обходе дерева. Таким образом, вам не нужно запрашивать дерево, чтобы получить список объектов, которые соответствуют «вопросу» связанного поля, вместо этого вы можете просто пройти вниз по дереву и выполнять этот обратный вызов каждый раз, когда вы что-то нажимаете. «Если этот связанный блок, который я предоставляю, пересекает вас, выполните этот обратный вызов с этими параметрами»
person
ralphtheninja
schedule
22.05.2009