1

我用 Java 编写了一个程序,圆圈可以相互反弹并相互吸引。

在大多数情况下(屏幕上的几个圆圈),没有明显的错误。当屏幕上有大量圆圈时,问题开始发生。有时,如果太拥挤,圆圈会重叠。就好像所有其他圆圈的重量正在将圆圈压在一起,导致它们重叠。当然,那里的程序不知道一个圆圈的重量,所以它并没有真正粉碎。最有可能的是,处理解决冲突的逻辑无法处理拥挤的情况。

圆圈存储在一个数组中,每个圆圈都使用 for 循环遍历数组,将自己与其他圆圈进行比较。如果这个圆的中心和另一个圆的中心之间的距离小于它们的半径之和,那么这些圆正在碰撞。使用碰撞方程更新两个圆的速度。

我认为问题的出现是因为如果一个圆圈被包围,它可能会在它后面的圆圈中接收到更新的速度,而它后面的圆圈也会在前一个圆圈中接收到更新的速度。换句话说,两个圆圈被告知要相互靠近,即使它们已经接触。一旦它们以这种方式重叠,我不知道他们为什么不撤消重叠。

如果它们重叠,我已经尝试通过找到它们重叠的距离来恢复触摸场景,然后将它们彼此分开;每个都将重叠距离的一半分开。这不会改变圆的速度,只会改变它们的位置。

这仍然不能解决问题。如果圆圈被包围,并且它与其中一个相邻的圆圈重叠,则它的位置会更改,因此它们不会重叠,但这个新位置可能会导致它与另一个圆圈重叠。同样的问题。

如果没有重力将这些圆圈推到一起,它们最终会散开并解决它们重叠的问题,但重力阻止了这种情况的发生。

更多信息:

在计算碰撞后的新速度时不考虑重力。

4

1 回答 1

4

听起来您对导致问题的原因的预感在这两种情况下都是正确的。

不幸的是,没有简单的方法来解决这个问题——这几乎意味着从头开始重写你的整个碰撞检测和解决代码。您必须计算出第一次碰撞的确切时间,仅更新到目前为止的所有内容,解决碰撞(进行速度更新)然后计算出下一次碰撞的确切时间,然后重复......

编写一个好的物理引擎很难,市场上有很多关于这个主题的教科书是有充分理由的!

解决您的问题的廉价“解决方案”是减少更新的时间间隔 - 例如,不要以 33 毫秒的步长 (~30fps) 更新物理,而是尝试以 16 毫秒的步长 (~60fps) 进行更新。这不会阻止问题的发生,但它会降低它发生的可能性。将时间步长减半也会使处理器花费在物理更新上的时间加倍!

如果您使用廉价修复,最适合您的时间步将取决于碰撞发生的频率 - 更多的碰撞意味着更小的时间步。碰撞发生的频率基本上取决于圆圈移动的速度及其人口密度(给定区域的多少被圆圈填充)。

更新:有关“正确”方法的更多信息。

更新将是这样的:

  1. 开始更新框架。假设我们要更新至 time tF
  2. 对于每一对圆圈,计算出您预计何时会发生碰撞(忽略所有其他圆圈)。这次我们打个电话吧tC
  3. 找到 的最小值tC。假设这是用于圆A和之间的碰撞B,我们称之为碰撞cAB
  4. 如果tC<= tF,更新所有的圈子 time tC。否则,转到步骤 6。
  5. 解决碰撞cAB。回到第 2 步!
  6. 将所有圆圈更新为 time tF

正如您可能想象的那样,这可能会变得非常复杂。第 2 步对于非圆形物体(尤其是当你包括角动量等)来说可能非常棘手(并且计算成本很高),尽管你可以在这里做很多技巧来加速它。基本上也不可能知道您将在第 2 步和第 5 步之间循环多少次。

就像我说的,做好物理模拟很难。实时进行就更难了!

于 2012-01-27T11:07:44.713 回答