You are on page 1of 14

使用

Javascript
製作
二維物理引擎
1547 06 張博崴
之前在使用 Three.js 製做 3D 遊戲時,曾經
使用過別人做的物理引擎 Cannon.js ,但是
有許多的功能或是函式我都不太了解要怎麼
用,又或者是沒有辦法達到我的需求,因此

動機 我就想著或許可以做出自己的物理引擎。

但是由於三維的物理碰撞對我來說可能過於
複雜,因此決定先試著製作二維的物理引擎,
完成後可以搭配 HTML5 的 canvas 畫布使用。
製作 • 製作原因
由於是要做二維的物理模擬,速度、加速度、位移等各種物理量都
是二維向量,因此若是有二維向量的模組可以使用,程式碼的可讀

二維向量模組 性將會變高許多,因此首先要做的就是二維向量的模組。
• 內容
我做了一個名為 vec2 的物件 ( 如左圖 ) ,有兩個屬性 x 和 y ,還
帶有十幾個函式用來計算。
• 新增方法
使用 new vec2(x 分量, y 分量 ) 新增新的向量
例 :let a=new vec2(0,0) 則 a 為 0 向量
• 計算方法
使用 vec2 裡面的函示來計算,若結果為一向量,則函式名稱
結尾為 _in 的會將結果覆蓋到自己,否則回傳一個新的向
量,若結果不是一個向量,則直接回傳結果。
例 :(v1,v2 為兩向量 )
v1.add(v2) => 回傳 v1+v2
v1.add_in(v2) => v1=v1+v2
v1.deg() => 回傳 v1 的角度
• 完整程式碼
我已經將每個函式加上註解並放上 github ,網址如下 :
https://github.com/weichang0307/vec2_module/blob/main/vect
or_md.js
物理引擎製 • 幾何物件 • world 物件
作方法 包含多個屬性,用來記 使用陣列紀錄所有加入到
我決定參考之前使用過的物 錄一個物體的速度、位 這個 world 的幾何物件,
理引擎,使用多個物件來製 置等數據。除此之外, 並由附帶的函式計算所有
還包含一些函式以方便 這個 world 裡的幾何物件
作 (class 方法 ) ,主要分為
使用。 的活動及互動,並改變他
world 以及不同幾何物件。 們的屬性數據。
* 由於目的是要模擬幾何物件的碰撞,因

幾何物件我只製作比較簡單的圓形 (ball)
和矩形 (rect) 。
* constructor() 為物件的建構函式

幾何物件
包含多個屬性以及一個繪圖用函式

矩形 球 ( 圓形 )
world 物件

屬性 屬性

• 迭代 (iteration) 較低 iteration 碰撞
由於碰撞的偵測是圖形重
疊時發生,因此為了要盡
量讓物體一接觸時就發生,
可藉由提高迭代次數,使 較高 iteration 碰撞
update 函式將時間切成更
多段來計算,由此提高精
確度。
函式
每次迭代將時間推進 time_(time/iteration) 毫秒

使用這個雙重迴圈可將 objs 陣列中的每


兩個物件進行碰撞檢測
( 不會重複檢測也不會跟自己檢測 )

* 每次迴圈的 i 跟 y 都是不
同的組合且 i 不會等於 y

update
一次 update

分成
iteration 次 矩形 - 矩形 圓形 - 圓形 圓形 - 矩形

碰撞 一次迭代

使用迴圈將每兩個幾何物件 重力及阻力
放入 collision 函式之後, 改變速度
要 雙重迴圈 分類碰撞種類
分成不同狀況交給不同的函 碰撞
改變速度 一組
示去做運算,並判斷是否需 collision
要再次進行碰撞檢測 ( 遞 判斷是否
速度 call back
迴) 改變位置
• 為何要遞迴 (call back)
紀錄初始速度,後 由於在碰撞之後物體的速度發生改
面用來檢測是否有 變,因此原本不成立碰撞的兩個物
碰撞發生 體可能發生碰撞,又或者是碰撞的
初速度發生了變化,因此要再次進
行碰撞檢測,不斷遞迴直到所有物
體都不再發生碰撞。
將四種可能的狀況
放入對應的三種碰 Ex:( 以下例子以右為正 )
撞函式中進行碰撞
的檢測與計算 以下為物體 A 、 B 、 C ,速度分別為 5 、
0、0
一開始 B 與 C 沒有碰撞。 5 0 0

經過第一輪的碰撞,各自的速度可能會變
成這樣,而此時 B 與 C
應該要發生碰撞。 0 5 0
若是速度發生改變
( 有碰撞發生 ) , 由於在第一輪 A 與 B 發生了碰撞,因此 A
則 與B
再次檢測與其他物 會與其他物體再次進 0 0 5
件是否有碰撞 行碰撞檢測,於是 B 與
C 發生碰撞。
此時已沒有物體會再發生碰撞,遞迴結束
碰撞函式
這裡就放上最簡潔的
球 - 球碰撞

其他的碰撞除了要先分類以外
概念大致相同,都是先將二維
碰撞簡化為某一方向上的一維
碰撞來做計算。

含註解的程式碼都放在 github
應用
程式碼的部分到此結束,以下是我對這次成果的一些應用
省思
以上就是完整的成果展示了,其實以上的程式碼已經是我精簡了好多次的最終成果,
畢竟一開始的程式碼有 700 多行,可讀性也很差。

但就算這已經是改良後的版本,我仍然發現了許多問題 :
1. 向量使用閉包導致效能不佳
2. 只能模擬完全彈性碰撞
3. 無法模擬物體的轉動
4. 無法模擬摩擦力

因此我打算繼續努力改良,同時提升我的物理能力,希望能夠造就功能更完善,效
能更好的物理引擎,甚至是將來有能力了我也想挑戰看看三維的物理世界。
以上就是這次計畫的完整成果報告,在過程中也遇到了許多困
難,一開始連彈性碰撞都不知道 ( 當時才高一 ) ,要找資料都
不知道要打什麼關鍵字,到現在做出了這樣一個可用度頗高的
一個模組,我想我在技術跟心理層面都成長了許多。

向量模組完整程式碼 :
https://github.com/weichang0307/vec2_module/blob/main/vector_md.js

總結 物理引擎完整程式碼 :
https://github.com/weichang0307/physic_module/blob/main/physic_md.js

You might also like