重力物理学,如何避免无限弹跳?

3
据我了解,实现重力的标准方法是在每个时间步骤中向对象的垂直向下速度添加一个数字(比如说9.8)。
然而,这种简单的数学方式会导致“无限弹跳”的问题,在我的程序中出现过(还有其他人也遇到同样的问题)。目前为止,简单的测试用例是一个球直接掉落并撞击“地板”。在碰撞时,球的矢量会被偏转并缩小1/4(作为占位符的恢复系数)。在每次时间步骤中,重力值(大约为2)会加到矢量上。结果是,球弹跳,然后越弹越低...... 然而,它不仅不能真正停下来,甚至不能显然停下来(这是真正的目标),它在屏幕底部上下颤动。调试输出显示,它的速度从未在几帧内降至低于2,因为该常量一直在不断地增加、取消和不断地再次增加。
现在,理解为什么不是难点。正如我一开始担心的那样,这就是我忽略了一些数学魔法的结果。但由于没有人讨论过这个问题,这让我想知道,解决这个问题的“典型”方法是什么? 编辑:经过相当长时间的工作,我已经确定仅使用单独的加速度值并不能解决问题——它仍然会尝试添加某个常数的重力分数。恒定时间步长意味着恒定的加速度;恒定的加速度意味着恒定的速度增加。弹跳时的恢复系数会使速度减小到一个点,并抵消加速度,但加速度将从0开始重新开始。如下所示:
1. 加速度从0开始,速度为y。 2. 加速度增加(grav * timestep)。 3. 速度增加加速度。 4. 重复2-3,直到与地板碰撞。 5. 加速度现在回到0。 6. 速度向量相应地反射,然后乘以CoR。 7. 重复2-3,随着速度由负转正。 8. 重复2-7,每次反弹保存的动量都比上次少。 9. 弹跳非常小。 10. 速度现在小于(grav * timestep)。 11. 与地面碰撞将加速度设置回0。 12. 加速度再次增加(grav * timestep)。 13. 速度增加加速度——现在足够一下子从负数转为正数。 14. 无穷地重复11-13。

现在,总的问题并不是速度永远不会等于0。这是可以预期的。但是,也可以预期的是一个无限递减的数字。当恢复系数设置为0.5时,反弹速度应该是上一次的一半,逐渐降低直到可以被丢弃为“停止”。通过引入纯粹的常数添加 - 无论是直接加速度还是将其添加到另一个值中,然后再添加到速度中 - 就会出现这个问题。我需要知道如何解决这个问题,具体来说。


为什么要将重力常数加到速度上?它应该应用于加速度。 - William Pursell
@WilliamPursell 目前还没有“加速度”值。球希望在时间步结束时到达x,y,并且重力会影响y的位置。我将研究真正的加速度值可行性。 - DigitalMan
1
这是由于您的集成方案存在缺陷。当球离地面太近时,速度增量必须是整个加速度值的一部分,因为球在撞击地面之前下落的时间不足一个完整的时间步长。 - Hristo Iliev
1
顺便提一句,运动是真正无限的 - 尽管球在每次弹跳后都会失去能量,但只有在无限次弹跳的极限情况下,能量才会达到0(即球会停止)。 - Hristo Iliev
1
只是提醒你,你描述的数值近似方法(欧拉方法)其实并不是标准的方法,因为它并不那么精确...如果你深入研究一下微积分,你会发现这实际上是一种相当糟糕的逼近微分方程的方法(而重力加速度就是这样一个方程)。在工业界中,“标准”方式是使用Verlet积分,它能够使误差随着时间步长的四次方而收缩,因为它处理速度和加速度的方式消除了欧拉方法的许多数值误差。 - Justin L.
2个回答

1

我刚刚处理了同样的问题。

这是解决问题的代码:

if (cat.y + cat.height >= ground.y)    // if the cat has hit the ground
{
    cat.y = ground.y - cat.height;    // reset to the bottom
    cat.vector.y = Math.round(COR * -cat.vector.y);    // might want to round down
}

这里重要的部分是四舍五入。

0
解决这个问题的唯一方法是当球碰到地面时,反转垂直速度并将球放置在障碍物上,这样球就会锁定在地面上,因为9.8/4的向上速度不足以“解锁”它并使其弹跳。

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