四叉树中巨大物体的问题

时间:2011-08-07 17:34:48

标签: 2d geospatial spatial quadtree

假设我有圆形物体。每个对象的直径为64像素。

我的四叉树的单元格比如96x96像素。

当我检查来自单元格的碰撞时,一切都会很好并且运行良好,一个圆圈位于+所有相邻单元格中。

但如果我有一个直径为512像素的圆圈怎么办?它将覆盖许多单元,因此当仅检查相邻单元时这将是一个问题。但是每次将更大的对象插入树中时,我无法重新调整四叉树网格的大小......

3 个答案:

答案 0 :(得分:2)

而是将对象放入单个单元格中,将它们放入它们碰撞的所有单元格中。这样你就可以单独测试每个细胞。使用指向对象的指针,这样就不会创建副本。此外,您只需要使用leavenodes进行此操作,因此无需将较高节点中包含的数据与较低节点组合。

答案 1 :(得分:1)

这是一个有趣的问题。也许您可以使用树高信息扩展节点或单元格?如果你有一个更大的对象,那么最小的单元格将它与树高嵌套。这就是地图的应用程序,如谷歌或bing地图。

这是指向类似解决方案的链接:http://www.gamedev.net/topic/588426-2d-quadtree-collision---variety-in-size。我把屏幕与四叉树混淆了。您可以通过简单的重复来检查碰撞。

答案 2 :(得分:0)

过度搜索

在搜索过程中,首先从最大的对象开始......

针对 QuadTreeNode.Centre.X 测试 Object.Position.X,以及

针对 QuadTreeNode.Centre.Y 测试 Object.Position.Y;

... 然后,通过获取差异的绝对值,只要绝对值不大于对象的半径,就将对象视为位于特定子节点内...

...也就是说,当物体的某些部分侵入该四边形时 :)

AABB(轴对齐边界框)也可以这样做

这里唯一真正需要注意的是,覆盖大部分屏幕的非常大的对象将强制搜索整个树。在这些情况下,可能需要采用不同的方法。

当然,这只会处理其他所有测试所针对的对象。为确保正确识别世界上所有其他大型对象,您需要稍微更改四叉树...

使用多种外观

在四叉树的这个变体中,我们只将对象作为指针放置在四叉树的叶节点中。较大的对象可能出现在多个叶节点中。

由于某些对象在树中具有多种外观,因此我们需要一种方法来避免它们,一旦它们已经被测试过。

所以...

一个简单的布尔值 WasHit 标志可以避免在一次命中测试中多次测试同一个对象……并且可以对所有“命中”对象运行“清理”,以便它们为下一次测试做好准备。< /p>

虽然这是有道理的,但如果执行全对全命中测试是浪费

所以...变得更聪明一点,我们可以通过在场景中的每个对象内部使用指针“ptrLastObjectTestedAgainst”来避免进行任何清理。这避免了在这次运行中重新测试相同的对象(第一次遇到后设置指针)

在针对场景测试新对象时不需要重置(新对象的指针值与上一个不同)。这避免了像使用简单的 Bool 标志那样重置指针的需要。

我在对象大小差异很大的场景中使用了后一种方法,并且效果很好。

弹性四叉树

我还使用了“弹性”四叉树。基本上,您对每个 QuadTreeNode 中可以理想地容纳多少项设置了限制 - 但是,与标准 QuadTree 不同的是,您允许代码在特定情况下覆盖此限制。

这里的首要规则是一个对象不能被放置在一个不能完全容纳它的节点中......顶部节点捕获任何大于屏幕的对象。

因此,小对象将继续“落入”以形成常规四叉树,但大对象不会一直落入叶节点 - 而是会扩展最后适合它们的节点。

将非叶节点视为“筛分”对象,因为它们从树上掉下来

事实证明,这对于许多场景来说都是一个非常有效的选择 :)

结论

请记住,这些标准算法是有用的通用工具,但它们不能替代考虑您的具体问题。不要“仅仅因为众所周知”而陷入使用特定算法或库的陷阱……您的应用程序是独一无二的,它可能会从稍微不同的方法中受益。

因此,不要只学习应用算法...学习这些算法,并以新颖和合适的方式应用这些原则本身。这些不是唯一的工具,也不一定最适合您的应用程序。

希望其中一些想法有所帮助。