使球弹跳停止

Make ball bounce to a stop

我有一个带有以下变量的球 class:

int x,y,width,height;
double velX,velY;

我想做的是,每当球撞到一个方块时,它就会反弹并失去一些速度。

//Gravity & movement for the ball
ball.setVelY(ball.getVelY() + 0.2);

ball.setY((int)(ball.getY() + ball.getVelY()));

//Make the ball bounce.
if(ball.getBounds().intersects(block.getBounds()){
     ball.setVelY(ball.getVelY() * -0.7);          
}

我认为这会使球缓慢反弹,直到大麦完全移动(我会对此进行测试,然后让球完全停止,)但事实并非如此。球会正常弹跳几次,每次弹跳都比前一次小。然而,在几次反弹之后,球将停止反弹低于之前的反弹。为什么会这样,我应该如何解决?

这里的问题是,您实际上是在离散地向球施加小的爆发力。即使您按比例缩小动量,您也会不断将 0.2 这个值添加到球的动量中。

打个比方,你通过周期性地施加重力所做的事情,就是在短时间内向下轻击球,给它动力。如果您想象一个静止的篮球在地面上或略高于地面,并且您开始快速敲击它,则可能会使球弹起。但是,如果您想象用手对球施加一个恒定的向下力(就像重力一样),那么球将不会反弹。

因为不可能让你的程序运行以连续的方式进行,所以可以说,你必须想办法解决这个问题。一种解决方案是简单地检查与地板碰撞时动量的最小阈值,如果低于该阈值,则将其动量设置为 0,并将其设置为与表面平齐。

问题可能是数字问题。你在写什么

ball.setVelY(ball.getVelY() + 0.2);
ball.setY(ball.getY() + ball.getVelY());

正在使用 Euler method 对微分方程进行积分。实际上,它是以下内容的简化:

ball.setVelY(ball.getVelY() + g * DeltaTime); // g = 9.8m/s² for earth gravity
ball.setY(ball.getY() + ball.getVelY() * DeltaTime);

其中 DeltaTime 是您的 积分时间步长 ,为简单起见,您将其设为一。

不幸的是,欧拉方法仅条件稳定,这意味着您可能会遇到速度发散(或这种永无止境的振荡)的情况。为了恢复稳定性,最好的方法是减少时间步长,在您的情况下这意味着降低速度,或者更确切地说是降低重力。尝试将 g 从 0.2 设置为 0.05,并将计时器的频率增加 4 以验证这一点。

如果你喜欢数学,你也可以看看无条件稳定的方法,比如 backward Euler method.