用于2D碰撞检测的四叉树

时间:2011-02-13 01:34:20

标签: data-structures collision game-physics quadtree

我正在尝试使用四叉树进行二维碰撞检测,但我对如何实现它感到有点困惑。首先,我有一个四叉树,其中包含四个子树(一个代表每个象限),以及一组不适合单个子树的对象。

当检查对象中树中的碰撞时,我会做这样的事情(感谢QuadTree for 2D collision detection):

  1. 检查对象是否与当前节点中的任何对象发生冲突。
  2. 对于空间与对象重叠的任何子树,递归。
  3. 要查找四叉树中的所有碰撞:

    1. 检查当前节点中的每个对象与当前节点中的每个其他对象。
    2. 针对每个子树检查当前节点中的每个对象。
    3. 要插入四叉树:

      1. 如果对象适合多个子树,则将其添加到当前节点,然后返回。
      2. 否则,递归到包含它的子树。
      3. 更新四叉树:

        1. 进入每个子树。
        2. 如果当前节点中的任何元素不再完全适合当前树,请将其移至父节点。
        3. 如果当前节点中的任何元素适合子树,请将其插入子树。
        4. 这样好吗?可以改进吗?

3 个答案:

答案 0 :(得分:35)

您的四叉树结构不是最佳的。您每个节点存储4个子树是正确的,但实际对象应该只存储在叶子内部,而不是内部节点。因此,需要将保存实际对象的集合移动到叶子上。

让我们看一下操作的实现

  1. 将对象插入四叉树
    检查对象是否与当前节点相交。如果是这样,递归。如果已达到叶级别,请将对象插入集合中。
  2. 从四叉树中删除对象
    执行与插入对象完全相同的步骤,但是当您到达叶级别时,将其从集合中删除。
  3. 测试对象是否与四叉树内的任何对象相交
    执行与插入对象完全相同的步骤,但是当您到达叶级别时检查是否与集合中的所有对象发生冲突。
  4. 测试四叉树内所有物体之间的所有碰撞
    对于四叉树中的每个对象,执行单个对象碰撞测试。
  5. 更新四叉树
    删除位置已被修改的四叉树中的所有对象,然后重新插入。
  6. 这有几个优点

    • 只在叶子中存储对象,很容易处理四叉树上的操作(特殊情况较少)
    • 四叉树可以有不同深度的叶子,因此您可以根据其覆盖的空间区域调整四叉树的密度。这种适应可以在运行时发生,从而保持对象/节点比率最佳。

    disatvantage

    • 对象可以属于四叉树中的多个集合。您将需要在四叉树外部使用额外的线性集合来枚举每个对象而不会重复。

答案 1 :(得分:6)

四叉树并不总是碰撞检测的最佳数据结构。四叉树的开销可能是无限的(如果你不限制树的深度),并且在最坏的情况下根本不提供任何加速。相反,您可能需要考虑使用稀疏网格,这样可以提供比四叉树更好的性能,而不会产生遍历多个树级别的额外开销。

还有其他完全不同的方法甚至可能更好。例如,您可以尝试实现Zomorodian和Edelsbrunner的算法,就像我在以下模块中所做的那样:

以下是我撰写的一些文章,更详细地讨论了这些问题:

特别是,如果你看一下上一节中的基准测试,你会看到所有被调查的图书馆,与其他碰撞检测方法(如R树,网格或细分树)相比,四叉树的表现往往很差。

答案 2 :(得分:0)

我不确定cpu的效果如何,但它似乎在eclipse中我的核心二人组正常工作,仍然以超过2400 fps的速度运行lol ..

基本上,我向可碰撞对象添加了一个列表,用于存储对与对象关联的四叉树节点对象的引用(通过插入到四叉树中)。我还为每个四叉树节点添加了一个列表,该列表存储对该节点范围内的任何对象的引用。因此每个节点只有一个对象出现。每个节点还存储对其父节点的引用,用于导航到附近节点,如果我想在初始节点之后检查它们中的任何节点以进一步确保碰撞准确性。

很容易获得对一个单元格中所有其他对象的引用:

list temp_checklist = object.cells[cell_index].objects
//('objects' being some sort of array or list of object references as described above)

希望能帮到某人;)