【互動藝術 DIY】用 p5.js 做一塊會呼吸的粒子背景
先問自己:阿哲會想動手嗎?
看完這個效果,阿哲可能會想:
「那如果我把粒子排成自己的名字,滑鼠靠近時會散開嗎?」
這就是正確的方向——讓讀者想自己動手改參數,而不是背程式碼。
這個方法厲害在哪?
p5.js 官網有很多炫技的粒子效果,但大部分只是給你看「很厲害」。
這次不一樣——我要教你用最少程式碼,做出最有呼吸感的互動。
秘密是:用「距離」控制行為,用「lerp」讓移動變溫柔。
教學順序
- 先建立粒子:讓一群點組成畫面
- 教動畫:用
sin()做出呼吸節奏 - 教距離感:用
dist()偵測滑鼠 - 教溫柔散開:用
lerp()柔和移動,不是瞬移 - 最後加美感:透明度、殘影、暖色
第一步:讓粒子回家
class Particle {
constructor(x, y) {
this.homeX = x; // 記住家的位置
this.homeY = y;
this.x = x;
this.y = y;
}
// 讓粒子回家的力量
returnHome() {
this.x = lerp(this.x, this.homeX, 0.05); // 每次移動5%的距離
this.y = lerp(this.y, this.homeY, 0.05);
}
show() {
noStroke();
fill(255, 180, 120, 200); // 暖橙色
ellipse(this.x, this.y, 4);
}
}
第二步:偵測滑鼠距離
function draw() {
for (let p of particles) {
let d = dist(mouseX, mouseY, p.x, p.y);
if (d < 100) {
// 滑鼠靠近時,輕輕推開
let force = 0.05 * (100 - d) / 100;
p.x += (p.x - mouseX) / d * force;
p.y += (p.y - mouseY) / d * force;
}
p.returnHome();
p.show();
}
}
第三步:加呼吸節奏
let breathPhase = 0;
function draw() {
breathPhase += 0.02;
let breath = sin(breathPhase); // -1 ~ +1 來回循環
background(10, 8, 5); // 暖暗色背景
for (let p of particles) {
let d = dist(mouseX, mouseY, p.x, p.y);
if (d < 100) {
let force = 0.05 * (100 - d) / 100;
p.x += (p.x - mouseX) / d * force;
p.y += (p.y - mouseY) / d * force;
}
p.returnHome();
p.show(breath); // 把呼吸相位傳進去
}
}
function show(breath) {
noStroke();
// 呼吸時變亮,吐氣時變暗
let alpha = map(breath, -1, 1, 150, 255);
fill(255, 180, 120, alpha);
ellipse(this.x, this.y, 4);
}
第四步:殘影效果
function draw() {
// 不要每幀清掉背景,而是蓋一層半透明黑色
fill(10, 8, 5, 30);
rect(0, 0, width, height);
// ... 其餘粒子邏輯
}
這樣粒子移動時會留下淡淡的光跡——很有沉浸式裝置的 feel。
阿哲可以怎麼玩?
| 參數 | 預設值 | 改成... | 效果 |
|---|---|---|---|
| 感知半徑 | 100px | 50px | 只有非常靠近才有反應 |
| 回家速度 | 0.05 | 0.02 | 超級慢,像在水裡 |
| 回家速度 | 0.05 | 0.2 | 快一點回覆 |
| 粒子數量 | 200 | 50 | 稀疏的星塵感 |
| 粒子颜色 | 暖橙 | 淡粉 | 更柔和的感覺 |
延伸練習
把粒子排成自己的名字:讓粒子組成「阿哲」或英文字母輪廓,滑鼠靠近時文字散開,離開後慢慢聚回來。
滑鼠不是破壞者,是一陣風:不只是排斥,而是讓粒子沿著滑鼠移動方向飄走。
做一個會呼吸的光圈:粒子圍成圓形,隨
sin()擴張收縮。滑鼠靠近時,圓形像水母一樣被推開。
知識圖譜連結
- p5.js 官網:p5.js 官方文件
- lerp():p5.js lerp()
- dist():p5.js dist()
- TeamLab 作品集:teamlab.art
Top comments (0)