过度搜索
在搜索过程中,首先从最大的对象开始......
针对 QuadTreeNode.Centre.X 测试 Object.Position.X,以及
针对 QuadTreeNode.Centre.Y 测试 Object.Position.Y;
...然后,通过取差值的绝对值,只要绝对值不大于对象的半径,就将对象视为位于特定子节点内...
...也就是说,当对象的某些部分侵入该四边形时:)
AABB(Axis Aligned Bounding Boxes)也可以做到这一点
这里唯一真正需要注意的是,覆盖大部分屏幕的非常大的对象将强制搜索整个树。在这些情况下,可能需要采用不同的方法。
当然,这只需要处理其他所有东西都在测试的对象。为确保正确识别世界上所有其他大型对象,您需要稍微更改四叉树...
使用多个外观
在 QuadTree 的这种变体中,我们仅将对象作为指针放置在 QuadTree 的叶节点中。较大的对象可能出现在多个叶节点中。
由于某些对象在树中具有多个外观,因此我们需要一种方法来避免它们已经被测试过。
所以...
一个简单的 Boolean WasHit 标志可以避免在一次命中测试过程中多次测试同一个对象......并且可以对所有“命中”对象运行“清理”,以便它们为下一次测试做好准备。
虽然这是有道理的,但如果执行 all-vs-all 命中测试是很浪费的
所以...变得更聪明一点,我们可以通过在场景中的每个对象内部使用指针“ptrLastObjectTestedAgainst”来避免进行任何清理。这避免了在此运行中重新测试相同的对象(指针在第一次遇到后设置)
在针对场景测试新对象时不需要重置(新对象的指针值与上一个对象不同)。这避免了像使用简单的 Bool 标志那样重置指针的需要。
我在对象大小差异很大的场景中使用了后一种方法,并且效果很好。
弹性四叉树
我还使用了“弹性”四叉树。基本上,您设置了每个 QuadTreeNode 可以理想地容纳多少项目的限制 - 但是,与标准 QuadTree 不同,您允许代码在特定情况下覆盖此限制。
这里最重要的规则是一个对象不能被放置到一个不能完全容纳它的节点中......顶部节点捕获任何大于屏幕的对象。
因此,小对象将继续“下落”以形成规则的四叉树,但大对象并不总是一直下落到叶节点 - 而是会扩展最后适合它们的节点。
将非叶节点视为“筛选”对象,因为它们从树上掉下来
事实证明,这对于许多场景来说是一个非常有效的选择:)
结论
请记住,这些标准算法是有用的通用工具,但它们不能替代考虑您的特定问题。不要陷入“仅仅因为它是众所周知的”而使用特定算法或库的陷阱……您的应用程序是独一无二的,它可能会受益于稍微不同的方法。
因此,不要只是学习应用算法......从那些算法中学习,并以新颖和合适的方式应用这些原理本身。这些不是唯一的工具,也不一定最适合您的应用程序。
希望其中一些想法有所帮助。