p5.js
IZCC 2025 wintercamp
-葉子齊-
p5 是由 Processing 延伸而成的 JavaScript 函式庫,
可以理解為Processing 的 JavaScript 版本。
它將許多繪圖、數學、物理模擬等函式封裝好,
讓我們可以直接使用。
會使用JS語法(你們週二顯至的課學過)
Text
(以上作品皆擷取自網路)
(以上作品皆擷取自網路)
主流的開發平台,上面有很多作品,也可以使用processing
p5.js Editor
<程式碼區>
<執行結果>
<執行>
<暫停>
每次更新程式就會自動執行
OpenProcessing
註冊
OpenProcessing
<執行><暫停>
<程式碼區>
<執行結果>
setup(): 在程式開始時只執行一次,設定畫布和初始化變數
draw(): 不斷重複執行,用來更新畫面和動畫
目前在p5.js中,分號可加可不加
createCanvas(width,height):創建畫布,可以設定長寬
background():設定背景顏色
createCanvas(width,height):創建畫布,可以設定長寬(單位是像素)
| 點 | point(x,y); |
| 線 | line(x1, y1, x2, y2); |
| 圓 | ellipse(x, y, w, [h]); |
| ellipse(x, y, w, h, [detail]); | |
| circle(x, y, d); | |
| 弧 | arc(x, y, w, h, start, stop, [mode], [detail]); |
| 矩形 | rect(x, y, w, [h], [tl], [tr], [br], [bl]); |
| 四邊形 | quad(x1, y1, x2, y2, x3, y3, x4, y4); |
| 三角形 | triangle(x1, y1, x2, y2, x3, y3); |
point(x,y);
function setup() {
createCanvas(400, 400);
background(100);
}
function draw() {
stroke(250);
strokeWeight(10);
point(100,100);
}line(x1, y1, x2, y2);
function setup() {
createCanvas(400, 400);
background(100);
}
function draw() {
line(100,100,200,200);
}ellipse(x, y, w, [h]);
function draw() {
ellipse(100,100,50,50);
}function draw() {
ellipse(100,100,50);
}未設定高度
則寬度和高度均使用寬度值
指定負高度或寬度
則取絕對值
function setup() {
createCanvas(100, 100, WEBGL);
background(100);
}
function draw() {
ellipse(0, 0, 80, 40, 6);
}決定在WEBGL模式下使用多少個頂點來繪製
(預設值為 25)
function setup() {
createCanvas(100, 100, WEBGL);
background(100);
}
function draw() {
ellipse(0, 0, 80, 40, 3);
}fill(180);
arc(50, 50, 80, 80, 0, PI + HALF_PI);0
PI + HALF_PI
fill(180);
arc(50, 50, 80, 80, 0, 1.5*PI);mode決定圓弧(arc)的填滿樣式
arc(50, 50, 80, 80, 0, PI + HALF_PI,OPEN);arc(50, 50, 80, 80, 0, PI + HALF_PI,CHORD);arc(50, 50, 80, 80, 0, PI + HALF_PI,PIE);OPEN半圓 (預設)
CHORD閉合半圓
PIE閉合餅形
arc(0, 0, 80, 80, 0, PI + QUARTER_PI, PIE, 5);rect(x, y, w, [h], [tl], [tr], [br], [bl]);
圓角半徑
rect(25, 25, 55, 50, 20, 50, 5, 30);tl
tr
br
bl
從左上到左下
20
50
5
30
rect(x, y, w, [h], [tl], [tr], [br], [bl]);
圓角半徑
rect(25, 25, 55, 50, 10, 30);rect(25, 25, 55, 50, 20);如果沒有把四個參數寫完
剩下的圓角半徑會以最後一個參數為準
20
20
20
20
10
30
30
30
function setup() {
createCanvas(700, 700);
background(0);
}
function draw() {
beginShape();
vertex(370,180);
vertex(310,290);
vertex(150,300);
vertex(300,385);
vertex(190,500);
vertex(375,450);
vertex(490,530);
vertex(440,380);
vertex(580,320);
vertex(420,290);
vertex(370,180);
endShape(CLOSE);
}function setup() {
createCanvas(700, 700);
background(0);
}
function draw() {
beginShape();
curveVertex(370,180);
curveVertex(310,290);
curveVertex(150,300);
curveVertex(300,385);
curveVertex(190,500);
curveVertex(375,450);
curveVertex(490,530);
curveVertex(440,380);
curveVertex(580,320);
curveVertex(420,290);
curveVertex(370,180);
endShape(CLOSE);
}| 背景 | background(); |
| 圖形填色 | fill(); |
| noFill(); | |
| 框線顏色 | stroke(); |
| noStroke(); | |
| 框線粗細 | strokeWeight(); |
background(0,100);background(0);
(100);
(200);
(255);
background(255,0,0);background(0,0,255);background(0,255,0);background(240,128,128);background('skyblue');background('white');background('#595959');background('#55D6BE');background('#FFD131');background('#FC6471');function setup() {
createCanvas(200,200);
background(255);
}
function draw() {
fill(255,106,106); //紅色圓
circle(100,100, 20);
fill(255,231,186); //黃色圓
circle(100,150, 20);
noFill(); ////無色圓
circle(130,125, 20);
}function setup() {
createCanvas(200,200);
background(255);
}
function draw() {
fill(255,106,106); //紅色圓
stroke(0,0,255);
circle(100,100, 20);
fill(255,231,186); //黃色圓
noStroke();
circle(100,150, 20);
noFill(); //無色圓
stroke(0,0,255);
circle(130,125, 20);
}function setup() {
createCanvas(200,200);
background(255);
}
function draw() {
fill(255,106,106); //紅色圓
stroke(0,0,255);
strokeWeight(5);
circle(100,100, 20);
fill(255,231,186); //黃色圓
strokeWeight(15);
circle(100,150, 20);
noFill(); //無色圓
stroke(0,0,255);
strokeWeight(2.5);
circle(130,125, 20);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
circle(mouseX, mouseY, 20);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
frameRate(5);
}
function draw() {
circle(mouseX, mouseY, 20);
}一般流暢動畫24FPS就好
function setup() {
createCanvas(500,500);
background(100);
}
function draw() {
rect(width/2, height/2, 100);
}function setup() {
createCanvas(500,500);
background(255);
}
function draw() {
noFill();
rectMode(CENTER);
rect(width/2, height/2, 100);
ellipse(width/2, height/2, 100);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
noStroke();
fill(191,239,255);
circle(mouseX, mouseY,50);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100,20);
noStroke();
fill(191,239,255);
circle(mouseX, mouseY,50);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100,20);
noStroke();
fill(mouseX,mouseY,255);
circle(mouseX, mouseY,50);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
function draw() {
background(100,20);
noStroke();
fill(frameCount,206,255);
circle(mouseX, mouseY,100);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
}
function draw() {
background(255,12);
fill(mouseX,mouseY,frameCount/2,frameCount/5);
triangle(440+mouseX/2,mouseY/2,300,300,mouseX,mouseY);
}| 目前滑鼠的 X 座標 | mouseX |
| 目前滑鼠的 Y 座標 | mouseY |
| 滑鼠左鍵是否被按下 (true/false) | mouseIsPressed |
| 被按下的滑鼠按鍵 (LEFT/CENTER/RIGHT) | mouseButton |
| 對應的鍵被按下被按下 | keyIsPressed |
function draw() {
background(0);
if (mouseIsPressed) {
if (mouseButton == LEFT)
circle(50, 50, 50);
if (mouseButton == CENTER)
triangle(23, 75, 50, 20, 78, 75);
if (mouseButton == RIGHT)
square(25, 25, 50);
}
}function draw() {
background(0);
if (mouseIsPressed)
circle(100,100,50);
}| 滑鼠左鍵是否被按下 (true/false) | mouseIsPressed |
|
被按下的滑鼠按鍵 (LEFT/CENTER/RIGHT) (左鍵/中鍵/右鍵) |
mouseButton |
| 一般鍵盤(要小寫) | 'a' 'w' 's' 'd' |
|---|
let x = 50;
let y = 50;
function setup() {
createCanvas(400, 400);
background(255);
}
function draw() {
if (keyIsPressed) {
if (key === 'w') {
y -= 1;
} else if (key === 's') {
y += 1;
} else if (key === 'a') {
x -= 1;
} else if (key === 'd') {
x += 1;
}
}
fill(0);
circle(x, y, 15);
}| key === 一般鍵盤 |
|---|
當使用 p5.js 偵測鍵盤時
需先點擊 canvas
| 方向鍵 | |
|---|---|
| 上 | UP_ARROW |
| 下 | DOWN_ARROW |
| 左 | LEFT_ARROW |
| 右 | RIGHT_ARROW |
let x = 50;
let y = 50;
function setup() {
createCanvas(400, 400);
background(255);
}
function draw() {
if (keyIsPressed) {
if (keyCode === UP_ARROW) {
y -= 1;
} else if (keyCode === DOWN_ARROW) {
y += 1;
} else if (keyCode === LEFT_ARROW) {
x -= 1;
} else if (keyCode === RIGHT_ARROW) {
x += 1;
}
}
fill(0);
circle(x, y, 15);
}| keyCode === 方向鍵 |
|---|
| 滑鼠左鍵按下又放開時 | mouseClicked() |
| 滑鼠左鍵按下時 | mousePressed() |
| 滑鼠左鍵放開時 | mouserReleased() |
| 滑鼠左鍵雙擊時 | doubleClicked() |
| 滑鼠移動時 | mouseMoved() |
| 滑鼠左鍵按住拖曳時 | mouseDragged() |
| 滑鼠左鍵按下又放開時 | mouseClicked() |
| 滑鼠左鍵按下時 | mousePressed() |
| 滑鼠左鍵放開時 | mouserReleased() |
| 滑鼠左鍵雙擊時 | doubleClicked() |
| 滑鼠移動時 | mouseMoved() |
| 滑鼠左鍵按住拖曳時 | mouseDragged() |
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
let fillColor = 0;
function mouseClicked(){
if(fillColor == 0){
fillColor = 255;
}else{
fillColor = 0;
}
}
function mousePressed(){
fillColor += 50;
if(fillColor > 255)
fillColor = 0;
}
function mouseReleased(){
stroke('deeppink');
}
function doubleClicked(){
stroke('royalblue');
}
function mouseMoved(){
fillColor = mouseX;
}
function mouseDragged(){
fillColor = mouseX/3;
}
function draw() {
fill(fillColor);
strokeWeight(10)
circle(width/2,height/2,250);
}| 隨機的亂數 | random(); |
|---|---|
| 連續的亂數 | noise(); |
回傳0-1之間的隨機浮點數(但不包含1)
0個參數
1個參數
回傳0-該數字之間的隨機浮點數
(但不包含該數字)(0-5、0-1000)
回傳從 -5 到 10.2 的值(但不包括 10.2)
2個參數
random();random(-5,10.2);random(5);
random(1000);function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
}
let arr = ['🫨','🤡','🤯'];
function draw() {
textSize(50);
if(mouseIsPressed)
text(random(arr),100,100);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
}
let arr = ['#E87461','#92DCE5','#F8F7F9','#F7EC59','#FF66D8'];
function draw() {
fill(random(arr));
ellipse(mouseX,mouseY,100,100);
fill(random(255),random(255),random(255));
rect(mouseX,mouseY,50,50);
}function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
}
let colors= "f7f9f9-bed8d4-78d5d7-63d2ff-2081c3".split("-").map(txt=>"#"+txt);
function draw() {
fill(random(colors));
ellipse(mouseX,mouseY,100,100);
}let colors= "".split("-").map(txt=>"#"+txt);噪聲本人
noise()就是在一維、二維、三維的噪聲上採點的噪聲上採點
採點
基本上random在初學階段就夠玩了
如果你很好學
可以參考下方連結
| lerp(start, stop, amt); |
|---|
| 依自訂比例在 A 與 B 之間取一個中間值 |
| map(value, start1, stop1, start2, stop2); |
|---|
| 將某個區間的數字對應到另一個指定區間 |
let x = map(mouseX, 0, 400, 0, 200);0
400
mouseX
0
200
0
100
200
300
50
100
150
function setup() {
createCanvas(400,400);
}
function draw() {
background(255);
strokeWeight(2);
line(0,0,0,400);
line(100,0,100,400);
line(200,0,200,400);
line(300,0,300,400);
line(400,0,400,400);
strokeWeight(20);
line(0, 40, mouseX, 40); //上面那條線
let x = map(mouseX, 0, 400, 0, 200);
// let x = map(mouseX, 0, 400, 0, 100);
line(0, 120, x, 120); //下面那條線
}function setup() {
createCanvas(600, 600);
background(200);
}
function draw() {
let color = mouseX;
// let color = map(mouseX, 0, width, 0, 255);
fill(color);
circle(width/2, height/2, 50);
line(255,0,255,height);
}var a = 20;
var b = 380;var c = lerp(a, b, 0.2);
var d = lerp(a, b, 0.5);
var e = lerp(a, b, 0.8);a(20)
b(380)
c(92)
d(200)
e(308)
0.2
0.5
0.8
function setup() {
createCanvas(400, 400);
background(255);
strokeWeight(30);
}
function draw(){
var a = 20;
var b = 380;
var c = lerp(a, b, 0.2);
var d = lerp(a, b, 0.5);
var e = lerp(a, b, 0.8);
stroke(0);
point(a, 200);
point(b, 200);
stroke(100);
point(c, 200);
point(d, 200);
point(e, 200);
print(c,d,e);
}let x = 200;
let y = 200;
function setup() {
createCanvas(400, 400);
background(200);
}
function draw() {
background(220);
// x = lerp(x, mouseX, 0.5);
x = lerp(x, mouseX, 0.05);
y = lerp(y, mouseY, 0.05);
circle(x, y, 50);
}
function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
}
function draw() {
noFill();
strokeWeight(5);
ellipse(200,200,200);
ellipse(200,200,250);
ellipse(200,200,300);
ellipse(200,200,350);
}(200,200)
想把中心點改成(300,300)?
想把中心點改成(300,300)?
function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
}
function draw() {
noFill();
strokeWeight(5);
var x = 300,y = 350;
ellipse(x,y,200);
ellipse(x,y,250);
ellipse(x,y,300);
ellipse(x,y,350);
}宣告變數
想改中心點只需要動變數的值
不需要一個一個手動改
先召喚一顆球
function draw() {
ellipse(50,50,50,50);
}var x = 50,y = 50;
function draw() {
ellipse(x,y,50,50);
}要讓球動起來
所以把球的X和Y改為變數
方便操控
讓球動起來
往右下角衝
draw(){}本身就會不斷重複執行
不需要再寫迴圈更改x,y
var x = 50,y = 50;
var vx = 3,vy = 5;
function draw() {
ellipse(x,y,50,50);
x += vx;
y += vy;
}令
x(水平方向)的速度(v)為3 -> vx = 3
y(垂直方向)的速度(v)為5 -> vy = 5
function setup() {
createCanvas(windowWidth,windowHeight);
background(0);
}
var x = 50,y = 50;
var vx = 3,vy = 5;
function draw() {
background(0);
ellipse(x,y,50,50);
x += vx;
y += vy;
}把軌跡蓋掉
再畫一次背景
現在的樣子
重力 -> 垂直方向速度加快
=> vy +=0.2
function draw() {
background(0);
ellipse(x,y,50,50);
x += vx;
y += vy;
vy += 0.2;
}解決沒有地板的問題
vy以向下為正
if y位置 > height(畫布高度)
速度轉向 且 反彈高度變低
function setup() {
createCanvas(windowWidth,windowHeight);
background(0);
}
var x = 50,y = 50;
var vx = 1,vy = 10;
function draw() {
background(0);
ellipse(x,y,50,50);
x += vx;
y += vy;
vy += 0.2;
if(y > height){
vy = -vy * 0.7;
}
}小球黏在地上
-> 反覆觸發if區塊
導致vy越來越小
y = height -> 不會反覆觸發
function setup() {
createCanvas(windowWidth,windowHeight);
background(0);
}
var x = 50,y = 50;
var vx = 1,vy = 5;
function draw() {
background(0);
ellipse(x,y,50,50);
x += vx;
y += vy;
vy += 0.2;
if(y > height){
vy = -vy * 0.7;
y = height;
}
}Finish
以上只是用變數做出物理的效果
更進階的方法
| 顯示文字 | text('文字',x,y); |
|---|---|
| 文字大小 | textSize(); |
| 取得文字字串的寬度 | textWidth(str); |
|
文字風格 一般,斜體,粗體,粗+斜體 |
textStyle(); NORMAL, ITALIC, BOLD, BOLDITALIC |
function setup() {
createCanvas(400,400);
background(255);
}
function draw() {
textSize(25);
textStyle(NORMAL);
text('Normal', 50, 15);
textStyle(ITALIC);
text('Italic', 50, 40);
textStyle(BOLD);
text('Bold', 50, 65);
textStyle(BOLDITALIC);
text('Bold Italic', 50, 90);
}找到p5.dom 把它打開
| 文字輸入框 | createInput(['預設文字']); |
|---|---|
| 按鈕 | createButton(['文字']); |
| 滑桿 | createSlider(min,max,[預設值],[間距]); |
| 顏色選取器 | createColorPicker(['預設顏色']); |
| 定位 | position(x,y); |
|---|---|
| 取值 | .value(); |
存入輸入框被輸入的文字
創建輸入框
var inputElement; //創建變數
function setup() {
createCanvas(200,200);
background(100);
inputElement = createInput();
}function setup() {
createCanvas(windowWidth,windowHeight);
background(100);
createInput();
}取得輸入框被輸入的文字
function draw() {
let txt = inputElement.value();
}定位輸入框
var inputElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
inputElement = createInput();
inputElement.position(50,50);
}顯示輸入框被輸入的文字
function draw() {
let txt = inputElement.value();
fill(255);
textSize(50);
text(txt,width/2,height/2);
}也可以先給一個預設值
var inputElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
inputElement = createInput("ZSISC");
inputElement.position(50,50);
}var inputElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
inputElement = createInput();
inputElement.position(50,50);
}
function draw() {
background(0);
let txt = inputElement.value();
fill(255);
//fill(txt);
textSize(50);
let textLength = textWidth(txt)+10;
for(var t=0;t<height;t+=60){
for(var i=0;i<width;i+=textLength){
text(txt,i,t);
}
}
}var sliderElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
sliderElement = createSlider(20,50,30,0.1);
sliderElement.position(50,50);
}
function draw() {
let sliderValue = sliderElement.value();
}var inputElement;
// var sliderElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
inputElement = createInput();
inputElement.position(50,50);
// sliderElement = createSlider(20,50,30,0.1);
// sliderElement.position(50,80);
}
function draw() {
background(0);
let txt = inputElement.value();
// let sliderValue = sliderElement.value();
fill(255);
textSize(50);
// textSize(sliderValue);
let textLength = textWidth(txt)+10;
for(var t=0;t<height;t+=60){
for(var i=0;i<width;i+=textLength){
text(txt,i,t);
}
}
}
var buttonElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
buttonElement = createButton('Go Crazy');
buttonElement.position(50,100);
buttonElement.mousePressed(goCrazy);
}
function goCrazy(){
//自訂
}
var inputElement;
var sliderElement;
// var buttonElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
inputElement = createInput();
inputElement.position(50, 50);
sliderElement = createSlider(20, 50, 30, 0.1);
sliderElement.position(50, 80);
// buttonElement = createButton('Go Crazy');
// buttonElement.position(50, 110);
// buttonElement.mousePressed(goCrazy);
}
function goCrazy() {
randomValue += 5;
// if(randomValue>0){
// randomValue = 0;
// }else{
// randomValue = 10
// }
}
// var randomValue = 0;
function draw() {
background(0);
let txt = inputElement.value();
let sliderValue = sliderElement.value();
fill(255);
textSize(50);
textSize(sliderValue);
let textLength = textWidth(txt) + 10;
for (var t = 0; t < height; t += 60) {
for (var i = 0; i < width; i += textLength) {
// text(txt, i + random(-randomValue, randomValue),
// t+random(-randomValue,randomValue));
}
}
}var colorPickerElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
colorPickerElement = createColorPicker('#F4D35E');
colorPickerElement.position(50, 150);
}
function draw() {
background(0);
let selectedColor = colorPickerElement.value();
fill(selectedColor);
}var inputElement;
var sliderElement;
var buttonElement;
// var colorPickerElement;
function setup() {
createCanvas(windowWidth, windowHeight);
background(0);
inputElement = createInput();
inputElement.position(50, 50);
sliderElement = createSlider(20, 100, 30, 0.1);
sliderElement.position(50, 80);
buttonElement = createButton('Go Crazy');
buttonElement.position(50, 110);
buttonElement.mousePressed(goCrazy);
// colorPickerElement = createColorPicker('#F4D35E');
// colorPickerElement.position(50, 150)
}
function goCrazy() {
// randomValue += 5;
if(randomValue>0){
randomValue = 0;
}else{
randomValue = 10
}
}
var randomValue = 0;
function draw() {
background(0);
let txt = inputElement.value();
let sliderValue = sliderElement.value();
// let selectedColor = colorPickerElement.value();
fill(255);
textSize(50);
textSize(sliderValue);
let textLength = textWidth(txt) + 10;
// let lineCount = 0;
for (var t = 0; t < height; t += 60) {
// lineCount++;
// if(lineCount%2==0){
// fill(selectedColor);
// }else{
// fill('white')
// }
for (var i = 0; i < width; i += textLength) {
text(txt, i + random(-randomValue, randomValue),
t+random(-randomValue,randomValue));
}
}
}將p5作品用網頁展示
把作品鑲嵌到一般的網頁中展示
github page
資料夾A
開啟p5的網頁
p5.js
一般的網頁
資料夾A
開啟p5的網頁
p5.js
一般的網頁
<body>
<div>
ZSISC<br>31st
</div>
<iframe src = "index.html"></iframe>
</body>iframe {
width: 100%;
height: 100%;
border: none;
z-index: -1;
position: absolute;
top: 0;
}回饋表單!
拜託填一下(⸝⸝⸝ᵒ̴̶̷ ⌑ ᵒ̴̶̷⸝⸝⸝)