Answers:
如果在四叉树中存储扩展对象(区域),则应从其接触的所有叶节点中引用该对象。我不会尝试找到最不常见的祖先并将其存储在那里,因为例如,碰巧穿过高层边界的一个小物体最终会到达一个很高的节点,并且必须针对那个大的其他物体进行测试,当您执行碰撞查询时的高级节点等。
但是,您还必须小心,因为最终可能会从多个节点引用大型对象,这使大型对象在移动时更新成本很高,并导致对其进行多次检查是否存在冲突等。取决于您的用例使用某种启发式方法在树中更高级别存储大型对象也许是值得的,但这会使算法复杂化,因此除非您确定在特定情况下确实存在性能问题,否则我可能不会打扰。
同样,要查询区域,查询应查看查询的区域接触的所有叶节点。
这些基本上使用相同的算法,即从一个区域开始,然后将其向下推入树中以找到其接触的叶节点。这是深度优先遍历,但是在每个节点上,您都可以修剪不接触该区域的所有子级。您需要维护一个堆栈以跟踪遍历的位置。
我将其添加为对@Nathan Reed的回答的评论,但它太大而无法发表评论,并且在任何情况下都值得作为单独的答案。
我们所做的正是他回答中提出的建议,实际上,在链接到此页面的消息源中有评论。在大多数情况下,它运行得非常好,除了每两三个月一次,我们一直在随机丢失一台服务器,该服务器由于大量搜索查询而变得无响应。
问题的根本原因引起了我的注意,同时进行了性能检查以尝试找出导致此问题的原因。如果您允许重叠的对象,则可能仅是一个问题。在我们的游戏中,我们这样做,并且在最坏的情况下,它有时会导致性能降低深度峰值。
我们有一个边缘案例,其中大约有100个带有边界磁盘的对象非常紧密地聚集在一起。这就导致了树中很尖峰的问题,因为我们到达了这样一个程度,即对象大于四叉树节点覆盖的区域,因此每个新对象都出现在多个节点中,从而导致对象的大量细分。树,从而使问题雪上加霜。
这样做的好处是,如果允许对象区域重叠,则在对象簇紧的情况下,请密切注意事物,以确保树不会变得太深。
我目前正在研究的解决方案是将对象存储为点,然后在执行搜索时,将搜索矩形的边界增加到树中存储的最大半径。这对我们应该有用,因为树是第一遍搜索,然后我们进行基于真实圆的范围检查以及其他一些条件检查,因此多余的错误警报将被过滤掉。
您的实际里程可能会有所不同。