如果我是你,我会从实现一个简单的 BSP(二进制空间分区)树开始。由于您在 2D 中工作,因此绑定框检查非常快。你基本上需要三个类:CBspTree、CBspNode 和 CBspCut(不是真的需要)
- CBspTree 有一个 CBspNode 类的根节点实例
- CBspNode 有一个 CBspCut 实例
- CBspCut 象征你如何将一个集合切割成两个不相交的集合。这可以通过引入多态性(例如 CBspCutX 或 CBspCutY 或其他一些切割线)巧妙地解决。CBspCut 也有两个 CBspNode
与分裂世界的接口将通过树类,如果您想用四叉树替换 BSP 解决方案,在此之上再创建一层可能是一个非常好的主意。一旦你掌握了窍门。但根据我的经验,BSP 就可以了。
如何在树中存储项目有不同的策略。我的意思是,您可以选择在每个节点中拥有例如某种容器,其中包含对占据该区域的对象的引用。这意味着(正如您问自己的那样)大项目将占用许多叶子,即会有很多对大对象的引用,而非常小的项目将出现在单个叶子上。
根据我的经验,这并没有那么大的影响。当然这很重要,但你必须做一些测试来检查它是否真的是一个问题。您只需将这些项目留在树中的分支节点上即可解决此问题,即您不会将它们存储在“叶级”上。这意味着您将在遍历树时快速找到这些对象。
当涉及到你的第一个问题。如果您只打算将此细分用于碰撞测试而没有其他用途,我建议永远不会碰撞的东西永远不要插入到树中。例如,正如您所说的导弹,不能与另一枚导弹相撞。这意味着您甚至不必将导弹存储在树中。
但是,您可能还想将 bsp 用于其他事情,您没有指定但请记住这一点(例如使用鼠标选择对象)。否则,我建议您将所有内容存储在 bsp 中,然后再解决冲突。只需询问某个区域中对象列表的 bsp 以获取一组有限的可能碰撞候选对象并在此之后执行检查(假设对象知道它们可以与什么碰撞,或其他一些外部机制)。
如果要加快速度,还需要处理合并和拆分,即当从树中删除事物时,很多节点将变为空,或者某个节点级别以下的项目数将减少到某个合并阈值以下. 然后,您想将两个子树合并为一个包含所有项目的节点。将项目插入世界时会发生拆分。因此,当项目的数量超过某个分割阈值时,您会引入一个新的切割,它将世界一分为二。这些合并和拆分阈值应该是两个常量,您可以使用它们来调整树的效率。
合并和拆分主要用于保持树的平衡,并确保它根据其规范尽可能高效地工作。这确实是您需要担心的。将事物从一个位置移动并因此更新树的速度很快。但是在合并和拆分方面,如果您过于频繁地进行合并和拆分,可能会变得昂贵。
这可以通过引入某种惰性合并和拆分系统来避免,即您有某种脏标记或修改计数。批处理所有可以批处理的操作,即移动 10 个对象并插入 5 个可能是一个批处理。完成这批操作后,您检查树是否脏,然后执行所需的合并和/或拆分操作。
如果您希望我进一步解释,请发表一些评论。
干杯!
编辑
树中有很多东西可以优化。但如您所知,过早优化是万恶之源。所以从简单开始。例如,您可以创建一些通用的回调系统,以便在遍历树时使用。这样,您不必查询树以获取与绑定框“问题”匹配的对象列表,而是可以遍历树并在每次遇到某些东西时执行该回调。“如果我提供的这个绑定框与您相交,则使用这些参数执行此回调”