所以,我做了一个简单的弹跳球模拟来学习哈斯克尔。球应该反弹到图像边界,并在重力作用下向下加速。
问题在于球随着时间的推移“神奇地”反弹。我希望它能保持相同的最大高度。
我怀疑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)
答案 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
弹跳过程中速度不会增加。
这仍然不完全准确,速度仍在上升,但速度较慢。