編程模擬自然(七):力學(xué)矢量與牛頓定律
序·后羿射日篇
舊書有云:古者十日并出,草木焦槁,一曰后羿者射日,太陽里之九鳥皆死,救蒼生于涂炭。
(前情提要:元一直在找尋離開月亮的機(jī)會(huì),但無名兒每天纏著元...)
...
“星星掛在天邊,就像夢(mèng)想遙不可現(xiàn)...”元哼唧著。
“猿叔你在哼什么曲子啊?”
“...星星消失在天邊,就像諾言來不及實(shí)現(xiàn)...”元對(duì)無名兒捂著雙耳選擇無視。
“咳咳,我這是在朗誦詩歌呢!”
...
第零章
“星星掛在天...你爸曾經(jīng)射落過太陽?”元?jiǎng)傄^續(xù)深情朗誦,似乎想到了什么。
“是的,聽娘說爹地最厲害了。”
“我不信,那你說他是怎么辦到的?”元不禁抬頭望了望天際那顆水藍(lán)色星球。
“用的是力學(xué)系統(tǒng)...”
“猿叔,你手中的粒子系統(tǒng)就內(nèi)嵌著呢!”無名兒繼續(xù)回答道
第一節(jié) 隨機(jī)游走
假設(shè)你站在一根獨(dú)木橋上,每 10 秒鐘拋一枚硬幣:如果硬幣正面朝上,你向前走一步;背面朝上,則向后退一步。這就是隨機(jī)游走——由一系列隨機(jī)步驟構(gòu)成的運(yùn)動(dòng)軌跡。
然后,從獨(dú)木橋轉(zhuǎn)移到地面,你就可以做二維的隨機(jī)游走了,不過每走一步需要拋擲兩次硬幣,而且需要按如下規(guī)則
| 第一次拋擲 | 第二次拋擲 | 結(jié)果 |
| 正面 | 正面 | 向前走一步 |
| 反面 | 正面 | 向右走一步 |
| 正面 | 反面 | 向左走一步 |
| 反面 | 反面 | 向后走一步 |
這是一個(gè)很簡(jiǎn)單的規(guī)則,但是隨機(jī)游走可以對(duì)現(xiàn)實(shí)世界中的各種現(xiàn)象建模:從氣體分子的運(yùn)動(dòng)到小孩一整天的玩耍活動(dòng)不一而足。
現(xiàn)在我們建立 Walker 對(duì)象,它表示一個(gè)可以隨機(jī)游走的對(duì)象,具有以下特點(diǎn):即維持了自身數(shù)據(jù)(位置),又能夠執(zhí)行某些動(dòng)作(比如繪制自身或者移動(dòng)一步)
首先,我們定義一個(gè) Walker 類——Walker 對(duì)象的模板
''' <summary> ''' 表示一個(gè)隨機(jī)游走對(duì)象 ''' </summary> Public Class Walker Public X As Integer Public Y As Integer End Class
構(gòu)造函數(shù)負(fù)責(zé)對(duì)象的初始化
''' <summary> ''' 初始化當(dāng)前對(duì)象的位置 ''' </summary> ''' <param name="initX">指定的對(duì)象位置X分量</param> ''' <param name="initY">指定的對(duì)象位置Y分量</param> Public Sub New(initX As Single, initY As Single) Me.X = initX Me.Y = initY End Sub
新建一個(gè) Move() 方法實(shí)現(xiàn)控制對(duì)象移動(dòng)
''' <summary> ''' 當(dāng)前對(duì)象隨機(jī)移動(dòng)一幀 ''' </summary> Public Sub RndMove() Dim chioce As Integer = Rnd.Next(4) '隨機(jī)值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
新建一個(gè) Walker 實(shí)例,并在一個(gè)過程里循環(huán)調(diào)用它的 RndMove() 方法,每次調(diào)用完畢就輸出到屏幕,我們就可以看到它的隨機(jī)運(yùn)動(dòng)軌跡

第二節(jié) 向量
這里指的是歐幾里得向量,即幾何向量。它的定義是:一個(gè)既有大小又有方向的幾何對(duì)象。在編程中,引入向量并不會(huì)給我們添加新工作,它會(huì)簡(jiǎn)化你的代碼,而對(duì)于在運(yùn)動(dòng)模擬中經(jīng)常出現(xiàn)的數(shù)學(xué)運(yùn)算,向量提供了很多現(xiàn)成的函數(shù)。
現(xiàn)在,將上述 Walker 類中的變量用向量等效替換。
Imports System.Numerics ''' <summary> ''' 表示一個(gè)隨機(jī)游走對(duì)象 ''' </summary> Public Class Walker Public Location As Vector2 Public Shared Rnd As New Random ''' <summary> ''' 初始化當(dāng)前對(duì)象的位置 ''' </summary> ''' <param name="initX">指定的對(duì)象位置X分量</param> ''' <param name="initY">指定的對(duì)象位置Y分量</param> Public Sub New(initX As Single, initY As Single) Location = New Vector2(initX, initY) End Sub ''' <summary> ''' 當(dāng)前對(duì)象隨機(jī)移動(dòng)一幀 ''' </summary> Public Sub RndMove() Dim chioce As Integer = Rnd.Next(4) '隨機(jī)值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> ''' 當(dāng)前對(duì)象物理仿真移動(dòng)一幀 ''' </summary> Public Sub NormalMove() Velocity = Velocity + Acceleration '更新速度 Location = Location + Velocity '更新位置 End Sub
容易知道三個(gè)向量間的作用關(guān)系是一種“涓滴”效應(yīng),加速度影響速度,進(jìn)而影響位置。

新建多個(gè) Walker 實(shí)例,并在一個(gè)過程里循環(huán)調(diào)用它的 NormalMove() 方法,并記錄下軌跡。

第三節(jié) 力與牛頓定律
我們首先要了解力在現(xiàn)實(shí)世界中的概念,力可以指代力量的強(qiáng)度,比如“她用力的推動(dòng)那塊大石頭”,或者“他有力地說出那句話”。但是這里是更書面化的概念,它源自牛頓運(yùn)動(dòng)定律:
力是一個(gè)向量,它使有質(zhì)量的物體產(chǎn)生加速。
當(dāng)看到定義的第一部分——力是一個(gè)向量,你應(yīng)該由衷的感到喜悅,同位置或加速度一樣,這在編程中可輕松被描述。
結(jié)合力的概念,我們需要看看牛頓三大運(yùn)動(dòng)定律。
牛頓第一運(yùn)動(dòng)定律通常簡(jiǎn)要的描述為:
物體有保持靜止或運(yùn)動(dòng)的趨勢(shì)。
這個(gè)表述遺漏了外力的作用,可以擴(kuò)展為:
除非有不均衡外力的作用,否則物體保持靜止或勻速直線運(yùn)動(dòng)狀態(tài)。
而在編程中,我們可以這樣表述牛頓第一定律:
在平衡狀態(tài)下,對(duì)象的速度向量(Vector 類型)始終都是常量。
然后先跳過牛頓第二定律,直接牛頓第三定律,它通常表述為:
每個(gè)作用力都有一個(gè)大小相等、方向相反的反作用力
這個(gè)表述容易引起誤解,可以更好的表述為:
力總是成對(duì)出現(xiàn)的,且這兩個(gè)力大小相等,方向相反
同樣地,這個(gè)表述也會(huì)引起誤解,因?yàn)樗雌饋硐袷钦f:成對(duì)出現(xiàn)的力總是會(huì)互相抵消,事實(shí)并非如此,成對(duì)出現(xiàn)的力不是作用在同一物體上的。
從編程角度表述牛頓第三定律:
若要計(jì)算一個(gè)由 A 施加在 B 上的作用力 F(Vector 類型),必須額外施加一個(gè)由 B 作用在 A 上的反作用力 -F
有時(shí)候不一定要遵循上述說法,比如模擬風(fēng)力效果時(shí),就不需要計(jì)算物體作用在空氣上的反作用力,因?yàn)楦静挥萌ツM空氣。
下面是牛頓第二定律,它被表述為:
合力等于質(zhì)量乘以加速度:F = M * A
現(xiàn)在我們用編程去模擬這條定律,結(jié)合力的累加原理和牛頓第二定律,新增 ApplyForce() 方法
Public Property Mass As Single = 10.0 '質(zhì)量大小 ''' <summary> ''' 指定的力作用于當(dāng)前對(duì)象 ''' </summary> ''' <param name="fVec">指定的力</param> Public Sub ApplyForce(fVec As Vector2) Acceleration = Acceleration + fVec / Mass End Sub
更新 NormalMove() 方法,需要將加速度清零
''' <summary> ''' 當(dāng)前對(duì)象物理仿真移動(dòng)一幀 ''' </summary> Public Sub NormalMove() Velocity = Velocity + Acceleration '更新速度 Location = Location + Velocity '更新位置 Acceleration = New Vector2(0, 0) '加速度清零 End Sub
現(xiàn)在,你可以創(chuàng)建任意的符合物理規(guī)律的一個(gè)力,并將它作用于 Walker 對(duì)象。
后記
“猿叔,你在做什么?”
“起草一份計(jì)劃書...”
“我問過我娘了,她不愿多說爹地的事情。”無名兒說話時(shí)有些失落。
“哈哈,就說是你編的嘛,射日的事我是不會(huì)相信的!”
“你最厲害,行了吧。”
“那是當(dāng)然,我可是創(chuàng)世神,誰能比我厲害。”元一副不可一世的樣子。
“喲,還創(chuàng)世神,你咋不上天咧?”
“....”
“你怎么知道我要上天?”元晃了晃手中的文稿。
中文名稱:后羿工程
英文名稱:Hou Yi Project
別稱:星際載人火箭登地工程
首席工程師:元
工程階段:論證中
工程目標(biāo):實(shí)現(xiàn)可載人登地
“唉,現(xiàn)在月球上好多偏遠(yuǎn)地方的孩子還上不起學(xué);”無名兒努力皺了皺眉。
“...”
“吳剛叔每天辛苦砍樹卻沒人給他發(fā)工資;”接著嘆了口氣。
“...”
“登地這種事又有什么意義呢?”
“所以?”
“你不要走唄,不然沒人陪我玩了。”
浙公網(wǎng)安備 33010602011771號(hào)