使用向量


向量可以用來表示具有方向與大小的任何東西,例如,在 p5.js 的畫布中,某點 (2, 3) 可以看成是 x 座標為 2 像素,y 座標為 3 像素的位置,至今為止的範例也是這麼做的,然而,也可以看成從原點開始,往 x 正方向移動 2 像,往 y 方向移動 3 像素的向量。

使用向量

在 p5.js 中,可以使用 createVector 來建立向量,傳回的是 p5.Vector 的實例,你也可以自行用 new 建立 p5.Vector 實例,例如以下都是建立向量 (2, 3):

const v1 = createVector(2, 3);
const v2 = new p5.Vector(2, 3);

建立 p5.Vector 的實例後,想知道向量的方向,可以透過 heading 方法,想知道向量的大小,可以透過 mag 方法。

用向量表示有什麼好處呢?至今為止只談過「點」,就用點來說明好了,兩個點 (2, 3)、(8, 4) 間的長度是多少呢?你是可以兩個點的 x 座標相減、y 座標相減,然後用畢式定理求出,不過,透過向量思考,搭配 p5.Vector 的方法,就可以簡單的取得:

const v1 = createVector(2, 3);
const v2 = createVector(8, 4);
const v3 = p5.Vector.sub(v2, v1);
console.log(v3.mag());

簡單來說,就是兩個向量相減,得到一個新向量,如下圖的綠色向量:

使用向量

你可以把綠色向量看成是以 (2, 3) 為原點的向量,這麼一來,透過 mag 求得其大小,就是兩個點 (2, 3)、(8, 4) 間的長度。

在向量的計算上,p5.Vector 實例的方法有許多都是可變動的,例如 addsubdivmult,計算後傳回狀態變動後的實例本身:

const v1 = createVector(2, 3);
const v2 = createVector(8, 4);
// 顯示 Vector {p5: p5, x: 6, y: 1, z: 0, constructor: Object}
console.log(v2.sub(v1.x, v1.y)); 

然而,透過 p5.Vector 的靜態方法,不會變動實例本身,而是為計算結果建立新實例傳回,這符合數學上的計算概念:

const v1 = createVector(2, 3);
const v2 = createVector(8, 4);
const v3 = p5.Vector.sub(v2, v1);
// 顯示 Vector {p5: p5, x: 6, y: 1, z: 0, constructor: Object}
console.log(v3);

p5.Vector 提供了許多方法可以使用,例如,雖然可以透過 heading 取得綠色向量的方向,然而,有時也會想知道它的單位向量,也就是大小為 1 的向量,這可以透過 normalize 取得:

const v1 = createVector(2, 3);
const v2 = createVector(8, 4);
const v3 = p5.Vector.sub(v2, v1);
// 顯示 Vector {p5: p5, x: 0.9863939238321437, y: 0.1643989873053573, z: 0, constructor: Object}
console.log(v3.normalize());

如果想知道從點 (8, 4) 出發,依綠色向量的方向,前進長度為 3 後的座標點會是多少,可以如下:

const v4 = p5.Vector.add(v2, v3.normalize().mult(3));

當然,想知道為什麼可以這麼計算,你必須得認識數學上,向量的計算是怎麼一回事,我在〈向量運算〉是有談到一些,網路上也有不少文件,臨時抱佛腳一下應該不會太難。

那麼之前文件的範例用向量表示會有什麼好處嗎?若將〈動畫控制〉中第三個範例,改用向量表示的話,旋轉的部份,就可以直接透過 rotate 方法:

在物理模擬方面,以向量來思考,可以簡化問題,搭配 p5.Vector 則可以簡化不少程式的撰寫,例如球在矩形中的碰撞,若球心的位置 center 一開始是 (1, 3),速度 velocity 一開始以向量表示為 (4, 3),也就是每秒等同於往 x 前進 4 像素,往 y 前進 3 像素,每次球心的新位置,就可以表示為 center + velocity,在碰到邊界時,只要將速度的 x 或 y 方向反向就可以了:

當然,畢竟每秒的更新速度是固定的,而速度向量一開始是 (4, 3),也就是看起來像碰到邊界才反彈,其實會下一次會超出邊界就反彈了,若就速度設得更大一些,就會明顯看到這個現象。