我用Java编写了一个程序,在这个程序中,圆圈可以相互反弹并相互吸引。
在大多数情况下(屏幕上的圈数很少),没有明显的错误。当屏幕上有大量圆圈时,问题就开始发生了。有时,如果圆圈过于拥挤,圆圈会重叠。这就好像所有其他圆圈的重量将圆圈压在一起,导致它们重叠。当然,程序对圆圈的重量一无所知,所以它并没有真正破碎。最有可能的是,处理解决冲突的逻辑部分无法处理拥挤的情况。
圆圈存储在一个数组中,每个圆圈使用for循环遍历数组,将自身与其他圆圈进行比较。如果该圆的中心与另一个圆的中心之间的距离小于它们的半径之和,则圆圈发生碰撞。两个圆的速度使用碰撞方程更新。
我认为问题的出现是因为如果一个圆圈被包围,它可能会在它后面的圆圈中获得更新的速度,而它后面的圆圈也会接收到前一个圆圈的更新速度。换句话说,两个圆圈被告知要相互移动,即使它们已经在触摸。一旦他们以这种方式重叠,我不知道他们为什么不撤消他们的重叠。
如果他们通过找到重叠的距离重叠,然后将它们彼此分开,我已经尝试恢复触摸场景;每个移动重叠距离的一半。这不会改变圆的速度,只会改变它们的位置。
这仍然无法解决问题。如果圆圈被包围,并且它与其中一个相邻圆圈重叠,则其位置会发生变化,因此它们不会重叠,但这个新位置可能会导致它与另一个圆圈重叠。同样的问题。
如果没有重力将圆圈推到一起,它们最终会扩散并解决它们的重叠问题,但重力会阻止这种情况发生。
更多信息:
在碰撞后计算新的速度时不考虑重力。
答案 0 :(得分:4)
在这两种情况下,听起来关于造成问题的原因都是正确的。
不幸的是,没有简单的方法来解决这个问题 - 它几乎意味着重写整个碰撞检测&从头开始解析代码。你必须弄清楚第一次碰撞的确切时间,只更新那里的所有东西,解决碰撞(做你的速度更新),然后计算下一次碰撞的确切时间,然后重复......
编写一个好的物理引擎很难,有一个很好的理由,市场上有很多关于这个主题的教科书!
您的问题的便宜'修复'是缩短更新的时间间隔 - 例如而不是以33ms步长(~30fps)更新物理,尝试以16ms步长(~60fps)更新。这不会阻止这个问题,但它会使它不太可能发生。将时间步长减半也会使处理器花费更多时间进行物理更新!
如果使用便宜的修复程序,最适合您的时间步长将取决于碰撞发生的频率 - 更多碰撞意味着更短的时间步长。碰撞发生的频率主要取决于圆圈移动的速度和人口密度(给定区域的多少由圆圈填充)。
更新:关于'正确'方法的更多信息。
更新将是这样的:
tF
。tC
。tC
的最小值。我们假设这是针对圈A
和B
之间的碰撞,让我们称之为碰撞cAB
。tC
< = tF
,请及时更新所有圈子tC
。否则,请转到步骤6. cAB
。回到第2步!tF
。正如您可能想象的那样,这可能会非常复杂。对于非圆形物体,步骤2可能相当棘手(并且声誉昂贵)(特别是一旦你包括角动量等等),尽管你可以在这里做很多技巧来加速它。基本上也不可能知道你将在第2步和第5步之间循环多少次。
就像我说的那样,做好物理模拟很难。实时做这件事更难!