编程模拟自然(七):力学矢量与牛顿定律
序·后羿射日篇
旧书有云:古者十日并出,草木焦槁,一曰后羿者射日,太阳里之九鸟皆死,救苍生于涂炭。
(前情提要:元一直在找寻离开月亮的机会,但无名儿每天缠着元...)
...
“星星挂在天边,就像梦想遥不可现...”元哼唧着。
“猿叔你在哼什么曲子啊?”
“...星星消失在天边,就像诺言来不及实现...”元对无名儿捂着双耳选择无视。
“咳咳,我这是在朗诵诗歌呢!”
...
第零章
“星星挂在天...你爸曾经射落过太阳?”元刚要继续深情朗诵,似乎想到了什么。
“是的,听娘说爹地最厉害了。”
“我不信,那你说他是怎么办到的?”元不禁抬头望了望天际那颗水蓝色星球。
“用的是力学系统...”
“猿叔,你手中的粒子系统就内嵌着呢!”无名儿继续回答道
第一节 随机游走
假设你站在一根独木桥上,每 10 秒钟抛一枚硬币:如果硬币正面朝上,你向前走一步;背面朝上,则向后退一步。这就是随机游走——由一系列随机步骤构成的运动轨迹。
然后,从独木桥转移到地面,你就可以做二维的随机游走了,不过每走一步需要抛掷两次硬币,而且需要按如下规则
第一次抛掷 | 第二次抛掷 | 结果 |
正面 | 正面 | 向前走一步 |
反面 | 正面 | 向右走一步 |
正面 | 反面 | 向左走一步 |
反面 | 反面 | 向后走一步 |
这是一个很简单的规则,但是随机游走可以对现实世界中的各种现象建模:从气体分子的运动到小孩一整天的玩耍活动不一而足。
现在我们建立 Walker 对象,它表示一个可以随机游走的对象,具有以下特点:即维持了自身数据(位置),又能够执行某些动作(比如绘制自身或者移动一步)
首先,我们定义一个 Walker 类——Walker 对象的模板
''' <summary> ''' 表示一个随机游走对象 ''' </summary> Public Class Walker Public X As Integer Public Y As Integer End Class
构造函数负责对象的初始化
''' <summary> ''' 初始化当前对象的位置 ''' </summary> ''' <param name="initX">指定的对象位置X分量</param> ''' <param name="initY">指定的对象位置Y分量</param> Public Sub New(initX As Single, initY As Single) Me.X = initX Me.Y = initY End Sub
新建一个 Move() 方法实现控制对象移动
''' <summary> ''' 当前对象随机移动一帧 ''' </summary> Public Sub RndMove() Dim chioce As Integer = Rnd.Next(4) '随机值0、1、2或3 If chioce = 0 Then X = X + 1 ElseIf chioce = 1 Then X = X - 1 ElseIf chioce = 2 Then Y = Y + 1 Else Y = Y - 1 End If End Sub
新建一个 Walker 实例,并在一个过程里循环调用它的 RndMove() 方法,每次调用完毕就输出到屏幕,我们就可以看到它的随机运动轨迹
第二节 向量
这里指的是欧几里得向量,即几何向量。它的定义是:一个既有大小又有方向的几何对象。在编程中,引入向量并不会给我们添加新工作,它会简化你的代码,而对于在运动模拟中经常出现的数学运算,向量提供了很多现成的函数。
现在,将上述 Walker 类中的变量用向量等效替换。
Imports System.Numerics ''' <summary> ''' 表示一个随机游走对象 ''' </summary> Public Class Walker Public Location As Vector2 Public Shared Rnd As New Random ''' <summary> ''' 初始化当前对象的位置 ''' </summary> ''' <param name="initX">指定的对象位置X分量</param> ''' <param name="initY">指定的对象位置Y分量</param> Public Sub New(initX As Single, initY As Single) Location = New Vector2(initX, initY) End Sub ''' <summary> ''' 当前对象随机移动一帧 ''' </summary> Public Sub RndMove() Dim chioce As Integer = Rnd.Next(4) '随机值0、1、2或3 If chioce = 0 Then Location = Location + New Vector2(1, 0) ElseIf chioce = 1 Then Location = Location + New Vector2(-1, 0) ElseIf chioce = 2 Then Location = Location + New Vector2(0, 1) Else Location = Location + New Vector2(0, -1) End If End Sub End Class
新增加速度和速度属性,并添加方法NormalMove(),
Public Velocity As Vector2 Public Acceleration As Vector2 ''' <summary> ''' 当前对象物理仿真移动一帧 ''' </summary> Public Sub NormalMove() Velocity = Velocity + Acceleration '更新速度 Location = Location + Velocity '更新位置 End Sub
容易知道三个向量间的作用关系是一种“涓滴”效应,加速度影响速度,进而影响位置。
新建多个 Walker 实例,并在一个过程里循环调用它的 NormalMove() 方法,并记录下轨迹。
第三节 力与牛顿定律
我们首先要了解力在现实世界中的概念,力可以指代力量的强度,比如“她用力的推动那块大石头”,或者“他有力地说出那句话”。但是这里是更书面化的概念,它源自牛顿运动定律:
力是一个向量,它使有质量的物体产生加速。
当看到定义的第一部分——力是一个向量,你应该由衷的感到喜悦,同位置或加速度一样,这在编程中可轻松被描述。
结合力的概念,我们需要看看牛顿三大运动定律。
牛顿第一运动定律通常简要的描述为:
物体有保持静止或运动的趋势。
这个表述遗漏了外力的作用,可以扩展为:
除非有不均衡外力的作用,否则物体保持静止或匀速直线运动状态。
而在编程中,我们可以这样表述牛顿第一定律:
在平衡状态下,对象的速度向量(Vector 类型)始终都是常量。
然后先跳过牛顿第二定律,直接牛顿第三定律,它通常表述为:
每个作用力都有一个大小相等、方向相反的反作用力
这个表述容易引起误解,可以更好的表述为:
力总是成对出现的,且这两个力大小相等,方向相反
同样地,这个表述也会引起误解,因为它看起来像是说:成对出现的力总是会互相抵消,事实并非如此,成对出现的力不是作用在同一物体上的。
从编程角度表述牛顿第三定律:
若要计算一个由 A 施加在 B 上的作用力 F(Vector 类型),必须额外施加一个由 B 作用在 A 上的反作用力 -F
有时候不一定要遵循上述说法,比如模拟风力效果时,就不需要计算物体作用在空气上的反作用力,因为根本不用去模拟空气。
下面是牛顿第二定律,它被表述为:
合力等于质量乘以加速度:F = M * A
现在我们用编程去模拟这条定律,结合力的累加原理和牛顿第二定律,新增 ApplyForce() 方法
Public Property Mass As Single = 10.0 '质量大小 ''' <summary> ''' 指定的力作用于当前对象 ''' </summary> ''' <param name="fVec">指定的力</param> Public Sub ApplyForce(fVec As Vector2) Acceleration = Acceleration + fVec / Mass End Sub
更新 NormalMove() 方法,需要将加速度清零
''' <summary> ''' 当前对象物理仿真移动一帧 ''' </summary> Public Sub NormalMove() Velocity = Velocity + Acceleration '更新速度 Location = Location + Velocity '更新位置 Acceleration = New Vector2(0, 0) '加速度清零 End Sub
现在,你可以创建任意的符合物理规律的一个力,并将它作用于 Walker 对象。
后记
“猿叔,你在做什么?”
“起草一份计划书...”
“我问过我娘了,她不愿多说爹地的事情。”无名儿说话时有些失落。
“哈哈,就说是你编的嘛,射日的事我是不会相信的!”
“你最厉害,行了吧。”
“那是当然,我可是创世神,谁能比我厉害。”元一副不可一世的样子。
“哟,还创世神,你咋不上天咧?”
“....”
“你怎么知道我要上天?”元晃了晃手中的文稿。
中文名称:后羿工程
英文名称:Hou Yi Project
别称:星际载人火箭登地工程
首席工程师:元
工程阶段:论证中
工程目标:实现可载人登地
“唉,现在月球上好多偏远地方的孩子还上不起学;”无名儿努力皱了皱眉。
“...”
“吴刚叔每天辛苦砍树却没人给他发工资;”接着叹了口气。
“...”
“登地这种事又有什么意义呢?”
“所以?”
“你不要走呗,不然没人陪我玩了。”