在第二篇文章我們完成了第一個作品,我們做出了分散在上下左右,能夠隨著滑鼠移動的四個圓圈。
現在我們希望在第二個作品做優化,讓這四個圓圈,還能繞著滑鼠做圓周運動,就像是行星繞著太陽一樣,那我們該怎麼做呢?
首先我們要先解釋一下 p5.js 中,畫布的 xy 座標系統,這個座標系統的原點 (0,0)
位於畫布的左上角,且 x 軸正向為由左到右,而 y 軸正向為由上到下:
當我們要做出圖案隨時間進行運動(圓周運動)的效果,就必須引入 frameCount
這個變數,該變數紀錄了目前 p5.js 執行了幾次 draw()
函數,也就是他繪製了多少幀動畫。
下面是第一個作品的程式,我們試著在裡面加入 frameCount
變數。
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100, 100);
circle(mouseX+100, mouseY, 20);
circle(mouseX-100, mouseY, 20);
circle(mouseX, mouseY+100, 20);
circle(mouseX, mouseY-100, 20);
}
現在我們開啟第二個作品的編輯界面,嘗試加入 frameCount
變數:
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100, 100);
circle(mouseX+100, mouseY + frameCount, 20);
circle(mouseX-100, mouseY + frameCount, 20);
circle(mouseX, mouseY+100 + frameCount, 20);
circle(mouseX, mouseY-100 + frameCount, 20);
}
我在每個圓圈的 y 座標都加上 frameCount
,因此除了會跟著滑鼠移動,他們還會因為 y 值的遞增,而逐漸往下移動,離滑鼠越來越遠:
那如果我們要使用這個 frameCount
來執行每個圓圈的圓周運動,那要怎麼做呢?
這裡就要稍微引入一下數學的向量概念:
上圖中的兩個箭頭分別代表向量 A (x1, y1)
跟向量 B (x2, y2)
,像這樣的二維向量,我們可以用一組 xy 座標來代表他。
然後這兩個向量他們的長度是一樣的,因此向量 A 和向量 B 這樣看起來就只有一個角度的轉向,然後這個角度就是 θ
。
重點來了,我們希望找到一個函數,他的輸入為 x1, y1, θ
,得到輸出為 x2, y2
,這個函數的用意在幹嘛呢?就是我希望輸入某個向量 (x1, y1)
跟某個角度 θ
,然後他要將這個向量 (x1, y1)
以逆時針轉 θ
度之後得到的新向量 (x2, y2)
給我們,所以這個函數是用來做向量旋轉的。
假設我們已經有了這個函數叫做 vector_rotate
,輸入向量就是圓圈相對於滑鼠的初始位置,角度為 frameCount/30
,輸出就是圓圈相對於滑鼠的新位置,現在初始位置固定,那隨著 frameCount
遞增,新位置所轉的位置也遞增,我們的圓圈不就可以繞著滑鼠做圓周運動了嗎?
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function vector_rotate(x, y, angle) {
...
}
function draw() {
background(100, 100);
// 這是初始位置
let [init_pos_x, init_pos_y] = [100, 0];
// 這是新位置
let [new_pos_x, new_pos_y] = vector_rotate(init_pos_x, init_pos_y, frameCount/30);
circle(mouseX+new_pos_x, mouseY + new_pos_y, 20);
}
若能夠完成 vector_rotate
的內容,那這段程式呈現出來的動畫會像這樣:
如果要實作 vector_rotate
,就必須要知道一些高中數學知識,在高中數學會學到一個矩陣叫做旋轉矩陣,就是用來做二維向量的旋轉:
我們不需要知道旋轉矩陣的實際細節,我們只需要借用他們的結果就行了,這個 vector_rotate
的內容就是:
function vector_rotate(x, y, angle) {
return [cos(angle)*x-sin(angle)*y,sin(angle)*x+cos(angle)*y];
}
現在我們能夠實現圓周運動了,那我們的第二個作品就是將第一個作品的四個圓圈加上圓周運動:
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function vector_rotation(x,y,angle) {
return [cos(angle)*x-sin(angle)*y,sin(angle)*x+cos(angle)*y];
}
function draw() {
background(100, 100);
let v = PI / 80 * frameCount;
let [x1, y1] = vector_rotation(100, 0, v);
let [x2, y2] = vector_rotation(-100, 0, v);
let [x3, y3] = vector_rotation(0, 100, v);
let [x4, y4] = vector_rotation(0, -100, v);
let y = mouseY;
let x = mouseX;
circle(x+x1, y+y1, 20);
circle(x+x2, y+y2, 20);
circle(x+x3, y+y3, 20);
circle(x+x4, y+y4, 20);
}
這是呈現出來的動畫: