多个物体之间的碰撞

6
我正在为娱乐编写一个简单的物理系统,但遇到了一个让我卡住的问题。
目前的基本算法是:
1. 移动一个物体 2. 检查碰撞 3. 如果发生了碰撞
- 将物体移动最小距离以解决碰撞。 - 根据法线、质量等调整速度。
我有一个移动的物体向两个静态无质量物体移动。
移动的物体在一步中被平移到与其中一个物体发生碰撞。
我通过寻找可以移动的最小距离来回应,以便它们不再碰撞。在这种情况下,这意味着将动态盒子向下移动。然而,现在它正在与另一个盒子碰撞。
我用那个箱子重复同样的事情,试图移动动态盒子,以使其不再碰撞,但这会将它推回第一个箱子。这将永远重复。我的算法基本上有缺陷吗?
2个回答

5

当检测到碰撞时,不应该向下移动,最好是向后移动到来时的方向。这样可以保证最终一定会处于无碰撞状态,前提是初始状态没有碰撞。

我们需要找出需要缩小(缩放)v以适应对象交集的大小。缩小后的v将具有正确的大小,因此如果我们朝着-v的方向向后移动相同的距离,则不再相交。

假设交集由x_intersectiony_intersection组成。为了找出需要向后移动多少才能不再相交,我们需要缩放原始的v = (v_x, v_y)向量。如果x_intersection是较小的交集,则我们通过x_intersection / v_x来缩放v,并将物体向后移动-v * x_intersection / v_x。这意味着我们向后移动-(x_intersection, x_intersection * v_y/v_x)。如果y_intersection是较小的交集,则我们通过y_intersection / v_y来缩放v,并将物体向后移动-v * y_intersection / v_y = -(y_intersection * v_x/v_y, y_intersection)

因此,我认为你算法的步骤应该是:

  1. Move object by some move vector v
  2. Check for all collisions
  3. If there was a collision

    • For all collision objects find the minimum scaling of v by which we we would need to move back. This scaling can be computed as the minimum of two ratios

      given v = (v_x, v_y)
      min_i = min(x_intersection / v_x, y_intersection / v_y)    
      
    • Find the minimum scaling ration across all objects.

      min_o = min(min_i) for all i
      
    • Move object back in direction of vector obtained by scaling the negative move direction with the minimum ratio. That is v2 = (min_o*-v) where v2 is the vector we use to move back.

  4. Go back to step 2
例如:首先选择w

w

然后选择u2

u2

完成:

enter image description here


1
漂亮的图像,但我认为你计算回退距离的数学有误。由于 min_o 可能是一个非常小的值,1/min_o 可能非常大。而且如果你看单位,似乎也有问题:vmin_o 都是距离,因此 -v/min_o 是无量纲的,你不能将其赋给距离向量 v2 。我不是很理解你如何定义 min_o,但你可能应该添加或减去一些东西,或者像我的答案一样,只需返回上一个位置并重新执行最小可能步骤即可。 - Bas Swinckels
@BasSwinckels 哎呀,是的,你说得对。我想做的是将 v 向量缩小到最小交点的大小,然后从 v 中减去它。但要做到这一点,如果最小交点在 x 方向上,则必须按 v_x / min_o 缩放,如果交点在 y 方向上,则必须按 v_y / min_o 缩放。否则,就像你说的那样,它是无量纲的。 - cyon
@BasSwinckels 好的,我已经编辑过了,我认为我修复了数学问题。新的缩放保留了单位,并且如果 min_o 非常小,则不会受到影响。这应该是正确的缩放方式,可以将 v 缩小到所需大小以适应对象交集。 - cyon
我认为这种方法不会很有效。如果我在平坦的表面上滑动,但由于与地面碰撞而向后进行时间步进,那么我将无法移动。 - X Builder

2

可能有一个解决方案可以对抗你所描述的问题(完全未经测试):

  1. 将对象移动一个完整的时间步长 dt

  2. 检查与其他对象的碰撞,这可能不止一个对象

  3. 通过插值计算“撞击时间”,这是小于时间步长的某个实数。对于每个你碰撞到的对象都要这样做,并选择最小的那个。这给出了到第一次碰撞的时间 t_col < dt

  4. 重新执行上一步,但现在只移动对象 t_col 以使其恰好撞击该对象,然后开始翻转速度和其他与碰撞相关的物理量。如果你懒得继续移动,则可以在此处完成步骤(可能可以,因为 dt 应该很小),或者继续移动另外的 dt - t_col 并查看是否撞到了其他东西。

这不是我刚刚发明的东西,而是类似于Simulink使用的零交叉检测,用于模拟这种不连续问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接