哈斯克尔的简单弹跳球不断弹跳

时间:2014-06-29 22:25:21

标签: haskell simulation physics

所以,我做了一个简单的弹跳球模拟来学习哈斯克尔。球应该反弹到图像边界,并在重力作用下向下加速。

问题在于球随着时间的推移“神奇地”反弹。我希望它能保持相同的最大高度。

我怀疑bounce而不是move有问题,因为bounce“将球传送回框架内部,这在身体上并不准确。我尝试了不同的方法来模拟正确的行为,但找不到任何正常的工作。

这样做的正确方法是什么?

以下是在CodeWorld上运行的代码:

main = simulationOf initial step draw

data World = Ball Point Vector

radius = 40
border = 250 - radius
g = -500

initial (x:y:vx:vy:_) = Ball (400*x  - 200, 400*y  - 200)
                             (400*vx - 200, 400*vy - 200)

step t world = bounce (move t world)

move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy + g*t)

bounce (Ball (x,y) (vx,vy)) = Ball (nx,ny) (nvx, nvy)
  where nx  = fence (-border) border x
        ny  = fence (-border) border y
        nvx = if nx /= x then -vx else vx
        nvy = if ny /= y then -vy else vy

fence lo hi x = max lo (min hi x)

draw (Ball (x,y) _) = translate x y (solidCircle radius)

2 个答案:

答案 0 :(得分:4)

这是你用来整合运动微分方程的算法中众所周知的神器。

“真实物理学”是(我只讨论 y 组件)

  

y /∂ t = v t
    ∂ v /∂ t = g

您可以通过高度和速度的离散序列对此进行建模

  

y i = y i - 1 + v i - 1 ⋅Δ t
     v i = v i - 1 + g⋅Δ t

这肯定类似于微分方程,只是写成差分商 - 但它不是一回事(除了限制Δ t →0):实际上,速度本身在时间内变化因此,在该时间步之前根据常量 v 值改变位置是不正确的。简单地忽略这种复杂性就是一种称为Euler's method的近似值,而且它已经很糟糕了。

更准确的标准替代方案是四阶Runge-Kutta method,试一试。

nm关于弹跳的观点也是有效的,但要真正做到这一点你应该计算确切的撞击时间,既不会忽视太多的加速也不会过多而实际上从未发生过

答案 1 :(得分:2)

假设球恰好在时间量的中间击中地面。实际上(或者说在无摩擦的“现实”中),速度的绝对值在量子的开始和结束时保持不变,但在你的模型中它会增加。

应该处理bounce中的加速。最简单的方法是这样做:

move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy)

step t world = bounce (move t world) t
bounce (Ball (x,y) (vx,vy)) t = Ball (nx,ny) (nvx, nvy) 
   ...
   nvy = if ny /= y then -vy else vy + g * t

弹跳过程中速度不会增加。

这仍然不完全准确,速度仍在上升,但速度较慢。