碰撞系统的正确数据结构选择

时间:2011-07-29 00:40:36

标签: data-structures collision-detection

我希望实现一个2D自顶向下碰撞系统,并希望能够对一些不同想法之间的可能性能进行一些输入。作为参考,我希望移动的碰撞对象的数量在几十个中,静态碰撞对象在几百个中。

第一个想法是边界线蛮力(或者可能不是边界线)。我会在碰撞系统中存储两个碰撞对象列表。一个列表是动态对象,另一个列表包括动态和静态对象(每个动态都在两个列表中)。每个帧我都会遍历动态列表并将每个对象传递给更大的列表,因此它可以找到它可能遇到的任何内容。这将涉及对任何合理大小的加载区域进行大量不必要的计算,但我将其用作一种基线,因为它很容易实现。

第二个想法是拥有一个包含所有碰撞对象的列表,以及一个表示加载区域的整数或浮点数的二维数组。数组中的每个元素都代表一个物理位置,每个对象都有一个大小值。每次对象移动时,它都会从旧位置减去其大小值并将其添加到新位置。在移动之前,对象必须访问数组中的元素,以确保新位置中有空间,但这样做很简单。除了我有一个非常公开,非常大的阵列,我认为它会表现得相当不错。我也可以使用布尔数组实现,只需存储一个位置是否已满,但我认为这对数字存储没有任何好处。

我的第三个想法是不太好。一两个月前,我读到了一个基于矩形的二维数据结构(可能是一棵树,我不记得了),它能够保持按位置排序的元素。然后我只需要将动态对象传递给他们的小邻居对象进行更新。我想知道是否有人知道这个数据结构可能是什么,所以我可以更多地了解它,如果是这样,它的每帧排序将如何影响相对于其他方法的性能。

真的,我只是在寻找关于这些将如何表现的想法,以及我可能忽略的任何陷阱。我并不担心实际的检测,因为这是使对象相互交流的最有效方法。

2 个答案:

答案 0 :(得分:3)

在这种情况下,你不是在谈论很多对象。老实说,即使在移动游戏开发中,你也可能会对它进行暴力破解,并且可能适用于你的应用程序。考虑到这一点,我建议你保持简单,但在肉汁上面放一些优化。具有合理单元大小的空间散列是我进入这里的方式 - 相对合理的内存使用,体面的加速,并且就实现的复杂性而言并不差。更多关于此的消息!

你还没有说过对象的表现形式,但无论如何你最终可能会遇到典型的“广泛阶段”和“狭窄阶段”(如物理引擎) - “广泛的阶段“由假阳性组成”可能相交的是什么?“查询和“狭窄阶段”暴力迫使产生的潜在交叉点。除非您使用二进制空间分区树之类的多边形形状,否则您不会最终得到单阶段解决方案。

如上所述,对于广泛的阶段,我会使用空间散列。基本上,您建立一个网格并标记与每个网格接触的内容。 (它不一定是完美的 - 它可能是每个网格中的轴对齐边界框,甚至。)然后,稍后您浏览网格的相关单元格并检查每个相关单元格中的所有内容是否实际与单元格中的任何其他内容相交。

Trick不是拥有一个数组,而是为每个单元网格都有一个哈希表。这样你就只占用了实际上有东西的网格空间。 (这是替换大小不合适的网格 - 你希望你的网格足够粗糙,不会在一个荒谬的单元格中有一个对象,因为这需要记忆,但你希望它没问题足以在几个单元格中没有所有对象,因为这不会节省太多时间。)通过目视检查,您将能够找出好的网格大小。

空间散列的另一个步骤...如果要保存内存,请丢弃通常在散列表中验证的索引。误报只会花费CPU时间,如果你正确地进行散列,它不会变得太多,但它可以为你节省大量的内存。

所以: 当您更新对象时,更新它们可能位于的网格。(同样,仅使用边界框就足够了 - 例如对象周围的方形或矩形。)将对象添加到哈希表中,用于它所在的每个单元格。 。(例如,如果你在单元格5,4中,哈希到哈希表的第17个条目。将它添加到哈希表的那个条目并扔掉5,4个数据。)然后,为了测试冲突,去吧通过哈希表中的相关单元格(例如,如果您感兴趣的话,整个屏幕的单元格值),并查看每个单元格内部的对象是否与每个单元格内的其他对象发生冲突。

与上述解决方案相比:

  • 请注意强制执行,花费的时间更少。
  • 这与所提到的“2D数组”方法有一些共性,因为毕竟我们在所表示的空间上强加了一个“网格”(或2D数组),但是我们这样做的方式不太容易精度误差(因为它仅用于保守的宽相)。此外,哈希表中的热量数据减少也减少了内存需求。
  • kd,sphere,X,BSP,R和其他“TLA”树几乎总是非常重要,无法正确实施和测试,即使经过所有这些努力,最终可能会比你期望的慢得多。对于几百个通常的对象,您不需要那种复杂性。

实施说明: 空间哈希表中的每个节点最终都是链表。我建议您仔细分配编写自己的链表。每个节点需要占用超过8个字节(如果您正在使用C / C ++)并且应该使用池化分配方案,这样您几乎不会分配或释放内存。依靠内置分配器可能会削弱性能。

答案 1 :(得分:1)

首先,我只是一个菜鸟,我正在通过3dbuzz xna extreme 101视频工作,我们现在正在覆盖一个使用每种不同类型对象的静态列表的系统,当你更新一个对象时检查它应该与之碰撞的事物列表。 因此,你只能检查敌人与玩家或玩家子弹的碰撞,而不是其他敌人等。

因此,每种类型的游戏对象都有一个静态列表,然后每个游戏节点都有自己的碰撞列表(编辑:节点列表),它们只是它可以命中的类型。

抱歉,如果不清楚我的意思,我还在找我的脚