实时计算碰撞 - 处理时间延迟

时间:2011-12-19 23:50:39

标签: math physics

假设:

  • 您正在编写一个程序,其中3个(或更多)圆圈(或其他几何体)在屏幕上实时移动,所有这些都具有不同的速度,由于物理原因可能会在特定时间发生变化-calculations。

  • 计算只能在每一帧计算

  • 每一帧,你必须确保那些“碰撞”/“在这帧和最后一帧之间发生碰撞的圈子”将通过使用物理计算来“反弹”

  • 假设在第x帧和第x + 1帧之间的时间内,三个圆圈将相互碰撞。但是,在帧x期间,没有一个圆圈接触另一个圆圈。在第x + 1帧中,同样适用(无碰撞) 我将尝试用图像更好地说明这一点:

enter image description here

问题:

有什么好的方法可以跟踪这样的碰撞,这样就不会因为两帧之间的某些(意外的)大延迟而跳过碰撞?

这个问题一直在我脑海里徘徊太久......

编辑:

对于每个人都认为这篇文章是OT:在投票结束之前见https://physics.stackexchange.com/questions/18515/calculating-collisions-in-realtime-dealing-with-a-delay-in-time

4 个答案:

答案 0 :(得分:2)

要做到这一点:

  • 为您的圈子计算精确碰撞时间,而不是舍入到下一帧:
    • 如果您的对象移动超过1D,则需要查找根目录。
  • 按顺序解决冲突,如下所示:
    • 在上述确切的碰撞时间停止模拟。
    • 解决第一次碰撞中圆圈的物理现象。
    • 重新计算以确定由于新轨迹引起的任何碰撞。
    • 重新开始模拟。
    • 重复,直到你没有碰撞到达帧尾。
  • 任何其他计划外的物理变化也需要更新即将发生的碰撞。

您可能会注意到这可能会进行大量计算。在你的球失去动能并最终相互靠近的情况下,这可能特别令人讨厌 - 如果你的物理学可能会这样做,你需要为“静止接触”添加某种阈值(不幸的是,这可能会使复杂化你的物理学非常好。)


更新,回应评论:我想说明我的答案忽略了你的一个假设 - 如果假装帧边界之间没有任何时间,你就无法准确处理碰撞。碰撞不会发生在边界处;一般来说,碰撞将发生在帧边界之间,因此你的计算需要反映出来。

如果您假设帧之间的所有运动都是线性的(即,您的模拟在帧边界上完成所有加速),那么确定是否,在何处以及何时发生碰撞实际上非常简单。它将您的帧间“模拟”简化为几乎没有 - 您可以以封闭形式求解方程式,即使您的模拟是2D或3D:

posAB = posA - posB                [relative vector between circles A and B]
velAB = velA - velB                [relative velocity between circles A and B]
posAB(t) = posAB(0) + t * velAB    [relative vector as a function of time]
rAB = rA + rB                      [sum of radii of the two circles]
collision happens when distance(t) = abs(posAB(t)) == rAB
-> rAB^2 = | posAB(t) |^2 = | posAB(0) + t * velAB |^2
-> t^2 * |velAB|^2 + t * 2*posAB(0).velAB + |posAB(0)|^2 - rAB^2 == 0
solve quadratic equation for t:
   - if discriminant is negative, there is no collision.
   - if collision times are outside current timestep, there is no current collision.
   - otherwise, smallest t should be the correct collision time.
   - watch out for cases like 2 circles coming *out* of collision...

最后,听起来你正在尝试过早优化。更好地使事情正常运转,然后让它们变得快速;在运行代码之前,您不会知道实际的瓶颈。事实上,我认为你低估了现代计算机的力量。当然,你总是可以添加足够的物品来摧毁你的电脑,但我想你会惊讶地发现它有多少......

答案 1 :(得分:1)

仅在“框架”中评估事物的想法可能不正确。

最古老的OO模式之一是“Model-View-Controller” - 它鼓励用如何查看正在查看的内容(模型)如何它被查看(视图)。

物理引擎对模型对象进行操作,因此跟踪它们之间的相互作用一直 - 所以当View出现并询问“Frame”中每个圆圈的位置和方向时x + 1“场景,它可以根据自上次查看请求以来经过的实际时间轻松回答。

答案 2 :(得分:1)

我知道你的问题表明物理学只能在每一帧进行评估,但我不明白何时会出现这种情况。只需足够小的步骤逐步更新物理,以避免物体完全绕过彼此,每个步骤一次。

但是,坚持明确的更新方案(速度时间步长)仅适用于低速度。从许多基于物理的游戏中可以看出,提高速度往往会导致穿透物体。 大多数简单的物理引擎选择只允许这些错误,因为强大的collision detection并不是非常困难和昂贵。

如果将适用性限制为仅仅是圆形,那么就有可能做到的事情。写入对象的距离,作为时间的函数(在时间步长上)

x_a = x0_a + v_a*t
x_b = x0_b + v_b*t
d_ab = norm(x_a-x_b) = norm(x0_b-x0_a + (v_b-v_a)*t) = norm(dx + dv*t)

如果距离函数d_ab等于时间步长期间任何r_a+r_b的半径t的总和,则表示您发生了碰撞。因此,首先检查哪些对象发生碰撞(如果有),然后从该点继续并重新进行分析,直到达到时间步骤结束。相当复杂,仍然只适用于圆圈/球体。

答案 3 :(得分:1)

此处碰撞检测的关键字是“连续”或“不连续”。

就像其他一些答案一样,大多数现代碰撞库都采用非连续版本,因为分析许多碰撞形状的精确碰撞时间成本很高。这意味着您让对象穿透,检测到它,然后调整它们的速度以抵消相互穿透。就像已经注意到的那样,这允许快速移动的物体相互通过。这可以通过提高运行物理的频率来解决,基本上你需要将它与渲染分离(使用更快的计时器运行它)。您解决相互渗透等问题的实际方法是针对不同的问题。

然而,对于圆形,您可以分析地求解具有恒定(或加速)速度的任何一对圆的精确碰撞时间,这使您有可能在此特定情况下进行连续碰撞检测。这将是一个不错的项目,但我不确定它是否是正确的方式,因为你可能突然想要包括其他形状然后你被卡住了。您必须解决的公式已作为答案发布。

除了总结这两种方法之外,我想在这里添加一些内容,因为你似乎非常关心“现代计算系统”的处理速度,现在计算机甚至以天真的方式快速地进行任何这些计算如果你在某种程度上优化内码,检查所有圈子对。为了解决非连续的高速情况,你可能没有任何问题可以提高物理速度与渲染相比。

为了避免对所有对象进行配对检查,非连续引擎添加的是使用某种数据结构来跟踪对象及其在空间中的一般位置和占用情况,以检测潜在重叠必须针对每个对象检查每个对象。这在商店谈话中被称为 broadphase 。如果你开始增加对象的数量,你肯定需要最终实现这样的东西。你没有说明你所瞄准的“大”圈数或CPU,所以希望你可以跳过这个并以简单的方式开始,但除非你发布你的用例,否则很难说。

底线:我会选择经过试验和测试的非连续发动机类型,以足够的物理频率来避免高速跳跃情况,并且不用担心性能问题。如果您真的有兴趣为游戏编码,并且不想处理细节,您可以简单地使用一些现有的2D物理库,如ChipmunkBox2D。我不熟悉他们的实现,但我确信如果你研究代码,它们也是学习这门课程的好方法。