要在虛擬世界中進行物理模擬,就是要模擬實體世界中物體的運動,實體世界中物體運動的基礎是牛頓運動定律(Newton's laws of motion):
- 第一定律:慣性,若施加於物體的外力為零,物體的運動速度不變。靜者恆靜,動者恆動。
- 第二定律:加速度,施加於物體的外力為質量與加速度的乘積。若 F 為力,m 為質量,a 為加速度,那麼
F = ma
。 - 第三定律:作用力與反作用力,兩物體互相施力於對方時,力的大小相等、方向相反。
為了模擬物體,需要有物體的位置,而模擬慣性定律時,因為沒有外力,只需要簡單地定義速度就可以了,p5.js 提供了 p5.Vector
,利用向量來定義位置與速度,在計算上就蠻方便的:
這邊要思考一個問題,實體世界中的速度是有單位的,那麼這邊的範例 velocity
單位是什麼?這要看你的虛擬世界是怎麼定義的。
就這邊來說,移動的單位是像素,update
設計為每次 draw
執行時呼叫,也就是頁框間的時隔為一個時間單位,位移量為時間乘上速度,也就是每次新座標可以單純地加上速度作為位移量。
運動定律不涉及形狀,Body
定義時也就不涉及形狀,形狀會涉及物體與物體之間的碰撞、受力的面積、角度等,是個複雜的議題,這邊在繪製形狀時,單純地使用圓,因為這是最簡單的形狀。
範例給定的速度是 (1, 1),執行結果就是圓從左上持續移動至右下,這是因為沒有任何外力改變或停止該物體,也就是動者恆動,如果範例給定的速度是 (0, 0),就是靜者恆靜了。
若要為物體套上力,就涉及第二定律 F = ma
,因而 Body
需要定義質量:
class Body {
constructor(coordinate, velocity, mass = 1) {
this.coordinate = coordinate;
this.velocity = velocity;
this.mass = mass;
}
applyForce(force) {
const acceleration = p5.Vector.div(force, this.mass);
this.velocity.add(acceleration);
}
update() {
this.coordinate.add(this.velocity);
}
}
那麼在這邊質量的單位是?同樣地,這要看你的虛擬世界是怎麼定義的,就這邊而言,會將一個像素就當為質量 1,也就是形狀佔的面積就會是質量,如果物體的形狀是圓,半徑為 r
,那麼就要在建構 Body
時給定 mass
為 PI * r * r
。
每次套用力後,速度就會改變,根據 F = ma
,a = F / m
,也就是速度的變化量,applyForce
中就是將之加至速度。
在這邊簡單地模擬一下球碰到邊界反彈,碰到邊界會反彈是因為第三定律,球被施予了反作用力,簡單地作法是直接改變速度的方向,不過這邊要透過 applyForce
,那麼反彈的力要怎麼算呢?
若物體速度為 (x, 0) 往右運動,碰到邊界的瞬間,速度會是 (-x, 0),也就是速度變化為 (-2 * x, 0),結合物體的質量 mass
,碰到邊界的瞬間,可看成受到 mass * (-2 * x, 0) 的反作用力。
來看看半徑為 10,初始速度 (2, 3) 的圓,在畫布中來回運動:
目前除了邊界反彈之外,還可以做些什麼呢?來試著在球上點一下,改變球的運動方向如何?這邊定義若點在球內,就施予一個點選處往球心的加速度,力道可以藉由 strength
來變化,範例中球一開始是沒有速度的,點選球來讓它運動吧!