QuadTree:仅存储点还是区域?


9

我正在开发四叉树,以跟踪移动物体以进行碰撞检测。每个对象都有一个边界形状,假设它们都是圆形。(这是一个二维的自上而下的游戏)

我不确定是否只存储每个对象的位置或整个边界形状。

如果使用点,则插入和细分很容易,因为对象永远不会跨越多个节点。另一方面,对对象的邻近查询可能会错过碰撞,因为它不会考虑对象的尺寸。只有点时如何计算查询区域?

来自相邻节点的对象之间的碰撞

如果使用区域,如何处理跨越多个节点的对象?即使它超出了节点的容量,也应该将其插入到完全包含它的最近的父节点中吗?

哪个节点应包含红色对象?

谢谢。

Answers:


4

如果在四叉树中存储扩展对象(区域),则应从其接触的所有叶节点中引用该对象。我不会尝试找到最不常见的祖先并将其存储在那里,因为例如,碰巧穿过高层边界的一个小物体最终会到达一个很高的节点,并且必须针对那个大的其他物体进行测试,当您执行碰撞查询时的高级节点等。

但是,您还必须小心,因为最终可能会从多个节点引用大型对象,这使大型对象在移动时更新成本很高,并导致对其进行多次检查是否存在冲突等。取决于您的用例使用某种启发式方法在树中更高级别存储大型对象也许是值得的,但这会使算法复杂化,因此除非您确定在特定情况下确实存在性能问题,否则我可能不会打扰。

同样,要查询区域,查询应查看查询的区域接触的所有叶节点。

这些基本上使用相同的算法,即从一个区域开始,然后将其向下推入树中以找到其接触的叶节点。这是深度优先遍历,但是在每个节点上,您都可以修剪不接触该区域的所有子级。您需要维护一个堆栈以跟踪遍历的位置。


谢谢,这很有意义。当然,处理跨节点对象要比完全位于节点内部的对象要慢,但是我看不出有什么办法。我可以增加节点容量以减少碎片,但这会增加冲突检测中包含的对象数量。我会解决这个问题,以找到一个平衡点。
alekop 2012年

4

您必须将其存储在完全包含它的最小节点中,即使这超出了容量(使用可调整大小的容器)。


2

我将其添加为对@Nathan Reed的回答的评论,但它太大而无法发表评论,并且在任何情况下都值得作为单独的答案。

我们所做的正是他回答中提出的建议,实际上,在链接到此页面的消息源中有评论。在大多数情况下,它运行得非常好,除了每两三个月一次,我们一直在随机丢失一台服务器,该服务器由于大量搜索查询而变得无响应。

问题的根本原因引起了我的注意,同时进行了性能检查以尝试找出导致此问题的原因。如果您允许重叠的对象,则可能仅是一个问题。在我们的游戏中,我们这样做,并且在最坏的情况下,它有时会导致性能降低深度峰值。

我们有一个边缘案例,其中大约有100个带有边界磁盘的对象非常紧密地聚集在一起。这就导致了树中很尖峰的问题,因为我们到达了这样一个程度,即对象大于四叉树节点覆盖的区域,因此每个新对象都出现在多个节点中,从而导致对象的大量细分。树,从而使问题雪上加霜。

这样做的好处是,如果允许对象区域重叠,则在对象簇紧的情况下,请密切注意事物,以确保树不会变得太深。

我目前正在研究的解决方案是将对象存储为点,然后在执行搜索时,将搜索矩形的边界增加到树中存储的最大半径。这对我们应该有用,因为树是第一遍搜索,然后我们进行基于真实圆的范围检查以及其他一些条件检查,因此多余的错误警报将被过滤掉。

您的实际里程可能会有所不同。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.