在上一個單元 p5.js 實戰演練(一) –– 疊合公轉軸,我們探討了怎麼在原有的圓周運動再疊加一層公轉軸,並描繪出畫布中四個 circle 的運動軌跡。
現在我們想再更進階一些,小公轉軸有 4 個 circle 做圓周運動,我們希望一個大公轉軸也會有四個小公轉軸做圓周運動,也就是說畫布上會出現 16 個 circle,這樣看起來也更加的一般化,每一個公轉軸剛好都繞著四個對象,不管是實際的 circle 或是更小的公轉軸。
不囉唆,先來上個完成結果:
這是軌跡版本:
現在我們的動畫更加迷人了一些,我們試著從原本的程式改成現在這個動畫的版本,以下是原 code:
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100, 10);
translate(width/2, height/2);
var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
var inner_orbit_speed = frameCount/60/3 * 2 * PI;
// 步驟一:定位小公轉軸的軸心
rotate(outer_orbit_speed);
translate(200, 0);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟二:繪製沿著小公轉軸繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
}
照著原本程式的邏輯,我們用一行定義了一個 circle,用了 8 行定義了一個小公轉軸的所有細節,現在有四個小公轉軸,那我們可能需要寫 32 行程式:
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100, 100);
translate(width/2, height/2);
var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
var inner_orbit_speed = frameCount/60/3 * 2 * PI;
// 步驟 1-1:定位小公轉軸 1 的軸心
rotate(outer_orbit_speed);
translate(200, 0);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
// 步驟 2-1:定位小公轉軸 2 的軸心
rotate(outer_orbit_speed);
translate(0, 200);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 2-2:繪製沿著小公轉軸 2 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
// 步驟 3-1:定位小公轉軸 3 的軸心
rotate(outer_orbit_speed);
translate(-200, 0);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 3-2:繪製沿著小公轉軸 3 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
// 步驟 4-1:定位小公轉軸 4 的軸心
rotate(outer_orbit_speed);
translate(0, -200);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 4-2:繪製沿著小公轉軸 4 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
}
我們分別用 translate(0, 200);
、translate(200, 0);
、translate(-200, 0);
、translate(0, -200);
來定義四個小公轉軸的位置,來看看結果如何:
...好欸,整個爛掉,到底是怎麼回事呢?
其實是當我們繪製完每個小公轉軸細節,就要校正回原本的大公轉軸座標系統,因為每個小公轉軸都會 call rotate(inner_orbit_speed);
,那看起來必須再 call rotate(-inner_orbit_speed);
校正旋轉,並進行下一個小公轉軸的繪製:
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100, 100);
translate(width/2, height/2);
var outer_orbit_speed = -frameCount/60/6 * 2 * PI;
var inner_orbit_speed = frameCount/60/3 * 2 * PI;
// 步驟 1-1:定位小公轉軸 1 的軸心
rotate(outer_orbit_speed);
translate(200, 0);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 1-2:繪製沿著小公轉軸 1 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
rotate(-inner_orbit_speed); // 校正回大公轉軸的座標系統
// 步驟 2-1:定位小公轉軸 2 的軸心
rotate(outer_orbit_speed);
translate(0, 200);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 2-2:繪製沿著小公轉軸 2 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
rotate(-inner_orbit_speed); // 校正回大公轉軸的座標系統
// 步驟 3-1:定位小公轉軸 3 的軸心
rotate(outer_orbit_speed);
translate(-200, 0);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 3-2:繪製沿著小公轉軸 3 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
rotate(-inner_orbit_speed); // 校正回大公轉軸的座標系統
// 步驟 4-1:定位小公轉軸 4 的軸心
rotate(outer_orbit_speed);
translate(0, -200);
rotate(-outer_orbit_speed); // 校正 rotate 函數對座標系統的轉動
// 步驟 4-2:繪製沿著小公轉軸 4 繞行的 4 個 circle
rotate(inner_orbit_speed);
circle(100, 0, 20);
circle(-100, 0, 20);
circle(0, 100, 20);
circle(0, -100, 20);
rotate(-inner_orbit_speed); // 校正回大公轉軸的座標系統
}
這是軌跡版本:
還是跟我們預期的不太一樣,但好像也蠻好看的 XD
寫 p5.js 有趣的地方就在這裡,有時候 bug 也會生出意料之外的視覺效果,但今天的內容已經夠多了,我們明天再來繼續實驗!