我在一个较大的项目中使用了四叉树,这对于移动不大的游戏对象(较少的移除和重新插入)很有用。同样的原则也适用于八叉树。
基本思想是,您创建一个递归树结构,其中存储 4 个(对于四边形)或 8 个(八角形)与树根相同类型的子对象。树中的每个节点代表笛卡尔空间的一部分,例如,每个适用轴上的 -100 -> +100。每个孩子代表相同的空间,但被细分为一半(示例的直接孩子将表示,例如,X 轴上的 -100->0 和 Y 轴上的 -100->0)。
想象一个具有给定尺寸的正方形或平面。现在在每个轴的中心画一条线,将该平面分成 4 个较小的平面。现在取其中一个,一次又一次地做,直到你到达一个平面段的大小大致是游戏对象大小的点。现在你有了你的树。只有占据同一平面的物体才有可能发生碰撞。当您确定哪些对象可以碰撞时,您会从它们生成可能的碰撞对。在这个阶段,broadphase 已经完成,您可以进入窄相碰撞检测,这是您进行更精确和昂贵计算的地方。
Broadphase 的目的是使用廉价的计算来生成可能的碰撞,并剔除不可能发生的接触,从而减少窄相算法必须执行的工作,进而使您的整个碰撞检测算法更加高效。
因此,在您继续尝试实现这样的算法之前,就像您自己一样:
我的游戏中有多少个对象?如果有很多,我可能需要一个广泛的阶段。如果不是,那么 Nnarrowphase 就足够了。另外,我是否在处理许多移动物体?
树结构通常会因移动物体而减慢速度,因为它们可以随着时间的推移改变它们在树中的位置,只需移动即可。这要求在每一帧(可能)中移除并重新插入对象,这比理想的要少。
如果是这种情况,最好使用 Sweep 和 Prune,它可以保持世界中形状范围的最小/最大堆。对象不需要重新插入,但堆需要在每一帧都重新使用,认为这通常比树宽、删除和重新插入遍历要快。
根据您的编码经验,一种编码可能比另一种更复杂。就我个人而言,我发现树对代码来说更直观,但效率较低,而且更容易出错,因为它们会引发其他问题,例如如果您有一个直接位于轴或中心顶部的对象该怎么办的根节点。这可以通过使用具有一些空间重叠的松散树来解决,这样当这种情况发生时,一个子节点总是优先于其他子节点。