当学习图形化编程(比如 Python 或者 Scratch)时,能写出模拟自然界的物理现象会很有趣,比如最常见的小球自由落体现象。为了写出逼真的小球下落轨迹,首先要了解背后的原理。
目录
原理
我们的图形化程序是基于帧来显示动画的。每隔一段时间,屏幕内容更新一次,称为一帧。为了模拟出自由落体的动画,我们的程序需要计算出每帧小球出现的位置。
想象一下用一个照相机,在小球下落过程中,每隔一段等长的时间,对小球的位置拍个照片。经过一段时间后,这些照片上小球的位置,就是我们要计算的数值。
模型
最简单的模型,是小球从静止状态自由下落。将重力加速度记为 g0g0 ,我们知道在任意时刻 tt,小球的速度是
v(t)=g0t=g0nTv(t)=g0t=g0nT
TT 为相邻两帧的间隔时间。上式中 g0g0, TT 都为常量,我们可以合并为一个新的常量 g1g1,这样 v(n)v(n) 构成了一个离散序列:
v(n)=g1nv(n)=g1n
或者
v(n)=v(n−1)+g1(1)(1)v(n)=v(n−1)+g1
速度 v(n)v(n) 是个等差数列,随时间变化的曲线如下图中的红线:
xyOLFhacks.com
为了简化问题,假设第 nn 帧到第 n+1n+1 帧之间,小球保持 v(n)v(n) 匀速,那么在两帧之间走过的路程为
Δy(n)=v(n)T=g1nT=gnΔy(n)=v(n)T=g1nT=gn
这里得到了第 nn 帧内,小球走过的路程。而第 nn 帧的小球位置 y(n)y(n) 是前 nn 帧内走过路程的累积:
y(n)=y(n−1)+gn(2)(2)y(n)=y(n−1)+gn
这里 gg 是一个常量,和真正的重力加速度的数值 9.8m/s29.8m/s2 已经没有关系,但是仍然起到了加速度的作用:这个值越大,小球下落的越快。位置 y(n)y(n) 的级差是等差数列,随时间变化的曲线如下图中的红线:
xyOLFhacks.com
这个曲线近似是抛物线 。在连续时间模型下,y(n)y(n) 的级差对应路程 s(t)s(t) 的导数,也就是瞬时速度 v(t)v(t). 级差是等差数列,则对应瞬时速度 v(t)v(t)是线性递增函数。
更深入的研究,请参看 蛙跳积分法 。
实现
用下面的伪代码可以实现上面的 (2)(2) 式:
var y=0, n=0, g=1
while(小球未落地)
y+=(n++)*g
这就是自由落体的代码实现。如下图所示:
(点击动画重新播放)
落地反弹
如何模拟当小球接触到地面后的反弹?
理想条件下,小球弹起的能量保持不变,速度数值不变,方向变为竖直向上。为了便于计算速度,将 上节的下落过程 改写为下面的伪代码:
var y=0, v=0, g=1
while(小球未落地)
v+=g
y+=v
这里 位置 yy 和速度 vv 是量纲不同的变量,不能直接相加,但这里这么写纯粹为了计算数值,效果和 上节 相同。接下来可以写小球反弹的场景:
var y=0, v=0, g=1
while(true)
if(小球触碰地面){
v=-v
}
v+=g
y+=v
效果如下图:
考虑损耗
由于摩擦的存在和小球的形变,反弹的一瞬间,有能量的损失,所以速度从数值上会减少。假设减少的数量和速度成正比,则剩余的速度是原速度乘上一个常数,记为 f,0<f<1f,0<f<1,那么上面的伪代码就变为:
var y=0, v=0, g=1, f=0.6
while(true)
if(小球触碰地面){
v=-f*v
}
v+=g
y+=v
效果如下图:
(点击动画重新播放)
(完)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/51838.html