# 第五周 --- tags: 程式設計,第三章,學生版,互動藝術程式創作入門,Creative Coding --- # 4.P 變數與資料 - 賦予可變與連續性(學生版) ## 單元介紹 我們會學到 * 了解「變數」是什麼 * 我們為什麼要使用變數 * 如何使用變數及注意事項 * 進階操作變數使創作更有效率、更有趣 - 什麼是變數? - 為什麼要用變數 - 開一個櫃子 放會使用到的東西 --- ## 程式碼開講 ### 產生三個圓 ![](https://i.imgur.com/MN6qGMY.png) --- ```javascript= ellipse(width/2,height/3,mouseX) ellipse(width/2,height/2,mouseX) ellipse(width/2,height*2/3,mouseX) ``` --- ### 由滑鼠游標的左右座標控制圓大小 --- ![](https://i.imgur.com/e2uLhHz.gif) --- ```javascript= function draw() { //background(220); ellipse(width/2,height/3,mouseX) ellipse(width/2,height/2,mouseX) ellipse(width/2,height*2/3,mouseX) ellipse(width/2,height*3/4,mouseX) ellipse(width/2,height/4,mouseX) ``` --- ### 讓游標越往左移動,中間的圓會亮度越黑 ```javascript= function draw() { //background(220); var r_x = mouseX/5 fill(mouseX%256,(184+frameCount)%256,3+mouseY/3) ellipse(width/2,height/3,r_x) ellipse(width/2,height/2,r_x) ellipse(width/2,height*2/3,r_x) ellipse(width/2,height*3/4,r_x) ellipse(width/2,height/4,r_x) } ``` ![](https://i.imgur.com/cLdpNCt.gif) --- ### 球移動的程式碼 * 設定一個圓圈,由左向右移動 ![](https://i.imgur.com/tiApFZI.gif) --- ```javascript= function draw() { background(220); var x=25 var y=25 var v_x=1//速率 ellipse(x,y,50) x=x+v_x } ``` --- ### 讓圓圈上下跳動 ![](https://i.imgur.com/2jcJ4QV.gif) --- ```javascript= function draw() {var x=25 var y=25 var v_x=5//速率 background(220); var x=25 var y=25 var v_x=5//速率 ellipse(x,y,50) x=x+v_x y=y+v_y v_y=v_y+0.2 if(y>height){ v_y=-v_y*0.8 y=height } } ``` --- #### 變數(文字) 讓圓圈與文字一起跳動 ![](https://i.imgur.com/9C9m3QD.gif) --- ```javascript= function setup() { createCanvas(windowWidth, windowHeight); background(0) } function draw() {var x=25 var y=25 var v_x=5//速率 background(220); var x=25 var y=25 var v_x=5//速率 ellipse(x,y,50) textSize("淡江大學") x=x+v_x y=y+v_y v_y=v_y+0.2 if(y>height){ v_y=-v_y*0.8 y=height v_y=-v_y*0.8 } } ``` --- #### 變數(布林值) 按下滑鼠左鍵,會變顏色 ![](https://i.imgur.com/xSrPps5.gif) --- ```javascript= function setup() { createCanvas(windowWidth, windowHeight); background(0) } function draw() {var x=25 var y=25 var v_x=5//速率 background(220); var x=25 var y=25 var v_x=5//速率 ellipse(x,y,50) textSize("淡江大學") x=x+v_x y=y+v_y v_y=v_y+0.2 if(y>height){ v_y=-v_y*0.8 y=height v_y=-v_y*0.8 ``` --- ### 製作一個磚牆 * 利用方塊製作一個磚牆 * 每塊產生的磚牆可以產生不一樣的顏色(以紅色為準)。 ![](https://i.imgur.com/OzwLyd0.gif) --- ```javascript= ``` --- ### 不同顏色的磚牆 ![](https://i.imgur.com/b57uv03.gif) --- 程式碼的修改 RGB三色都用亂數產生 ```javascript= ``` --- 完整程式碼 ```javascript= ``` --- 說明map 與lemp ```javascript= ``` ![](https://i.imgur.com/BqMDy69.gif) --- ## 一個利用圓弧產生的時鐘 透過 p5 內建方法拿到當前的時分秒,再用 map() 把時間對應到可以用在 arc() 上面的弧度,是很好用的技巧! ![](https://i.imgur.com/TSpd9Qi.gif) --- ```javascript= ``` --- ## 課程重點 ### 什麼是「變數」 (variable)? 「變數」是程式語言中非常重要的概念。你可以想像它其實像一個抽屜,可將某些資料儲存起來。只要呼叫這個抽屜的名字就可以取用存在其中的資料。 在 JavaScript 中,變數宣告的語法為: --- ```javascript= var r = 100 // 概念像是把 100 這個「數字」儲存在叫做 r 的這個抽屜中 var txt = '你好' // 也可以存「字串」在裡面 ``` 取用變數的方法:呼叫它的名字! ```javascript= print(r) // 透過 print() 把 r 的內容印出來。結果會是 100 print(txt) // 會印出「'你好'」 ``` - NOTE : 在程式語言中,‘=’ 代表「賦予數值」,‘==’ 才是數學中的「等於」! --- ### 為什麼要用變數,變數哪裡好用? * 減少重複的數值,程式碼管理起來更方便 例如畫多個相同半徑的球時,可以快速同時改變他們的半徑。 --- ```javascript= var r = 50 ellipse(width/2, height/3, 50) ellipse(width/2, height/2, 50) // 這兩個圓半徑重複了 ellipse(width/2, height/3, r, r) ellipse(width/2, height/2, r, r) // 這樣更好管理! ``` --- * 暫存之後可能會用到的資料 利用變數的特性,先將經過運算的資料儲存起來,等到要用時再呼叫。 例如下面的寫法就會比上面乾淨明瞭: --- ```javascript= // 不使用變數的寫法 //.....某些程式碼 fill(r/2 + 40, mouseX/2 +40, mouseY/2 +40 + mouseX/5) // 要用到顏色了,來直接運算!但這樣看起來很醜... // 使用變數的寫法 var brightnessR = r/2 + 40 var brightnessG = mouseX/2 + 40 var brightnessB = mouseY/2 + 40 + mouseX/5 // 這些算好後先準備起來 //.....某些程式碼 fill(brightnessR, brightnessG, brightnessB) // 要用到顏色囉,這樣好看多了! ``` --- * 做較複雜運算時能夠解構、梳理並進一步清晰邏輯 我們可以直接拿變數再做進一步處理並存起。這能讓變數間的邏輯關係更清晰,而且你也不用在意原先的變數是怎麼來的。 --- ```javascript= var halfWidth = width/2 // 要一半視窗寬度,直接拿 width ``` 來用!你也不用在意 p5 到底是怎麼去抓到視窗寬度 再以上面顏色的例子來說,若我沒有取用原先做好的變數來運算: ```javascript= var darkR = (r/2 + 40)/2 var darkG = (mouseX/2 + 40)/2 var darkB = (mouseY/2 + 40 + mouseX/5)/2 fill(darkR, darkG, darkB) ``` 跟這個相比: ```javascript= var darkR = brightnessR/2 var darkG = brightnessG/2 var darkB = brightnessB/2 // 反正我要更暗的,直接拿原先的 brightness 除以 2 就好了 fill(darkR, darkG, darkB) ``` --- 後者一眼就知道 dark 是拿原先的 brightness 來砍半。因此透過如此撰寫, --- * 保留先前的狀態,並藉此形成連續的狀態變化 這是變數運算特性的應用。我們可以把某些狀態,例如位置、大小、顏色等狀態先設定為變數,然後以先前的值運算並放回原先變數中來複寫舊內容,藉此來實現動態且連續地改變變數內容。 例如把球的位置設定為 x, y 兩個變數,我們透過以上技巧就可以畫出球移動的效果: --- ```javascript= // 球會往畫面右下方移動 var x = 50, y = 50 function draw(){ ellipse(x, y, 50) // 會取到更新的 x 及 y 位置資訊,並藉此畫出圓 x = x+5 // 每次都拿原先的 x 來加 5,並塞回原先的 x y += 5 // 等同於 y = y+5,只是簡略寫法 } ``` --- * 賦予數值與資料意義 對於電腦來說這些變數其實也只是一堆數字。所以變數的命名除了可以讓我們呼叫之外,最主要是為了讓人類自己可以看得懂,並且透過這些名字建立邏輯關係以方便我們操作跟編寫 ```javascript= var ballPositionX = 200 // 指「球的 x 位置」 var ballSize = 15 // 指「球的大小」 var rectFillColor = 'red' // 指「矩形的填充色」 ``` ## 變數可以裝哪些東西(資料型態)? ### 基礎的資料型態: * <font color="red">數字</font>: 0,1,2,-1,-2,0.1,0.2 … 各種可以被用來計算的數字 * <font color="red">字串</font>:'yellow', 'pig', '範例好難'… 可以簡單的想像成是被包覆起來的一段文字 * <font color="red">boolean</font>:即所謂「布林變數」,是用來判斷邏輯正確與否的。只會有true/false兩個值,也就是「是」或「不是」。 例如把 p5 的 <font color="red">mouseIsPressed</font> 打印出來,就只會看到 true 或是 false,分別代表有按下去 / 沒按下去。我們在使用 if() 判斷式的時候也會使用到 boolean 的概念呦! ## 變數的命名方式與習慣 * 要言之有意:例如<font color="red">滑鼠的位置命名</font>為 mousePos 會比 asdfgqwert 來的清楚明白,協助以後的自己與同事更好地了解程式碼。 * 駝峰式命名 (Camel case):若變數的名字是由多個單字構成,規則是頭一個單字的字首小寫,其他單字字首大寫,例如 var camelCase = '駝峰式命名規則'。 * 避免使用到語法 / 套件的保留字:JavaScript 內建的 function, window, alert ,或是 p5 的 width, height, mouseX, mouseY 之類的都要避免,以免造成程式錯誤。命名前可以參考ㄧ下 p5 的文件 或是 JavaScript 的保留字。 ## 範例練習 ```javascript= function setup() { createCanvas(windowWidth, windowHeight); background(0); stroke(0) strokeWeight(2) x=0 y=height/2 // strokeWeight(0.1) } // var number = 1 var x = 0 var y = 0 var r = 30 var vy = 0 var sec = 0 function draw() { // background(0,5) // print(number) //--------- px=x py=y x=x+2 y=y+vy vy=vy+0.5 if (y>height){ vy=-vy } //--------- x+=random(-5,5) y+=random(-5,5) // if (second()!=sec){ // sec=second() // x=random(width) // y=random(height) // r=random(50) // } fill(map(y,0,height,0,255),map(x,0,width,0,255) ,50) ellipse(x,y,r,r) // stroke(255) r+=random(-5,5) line(x,y,px,py) if (mouseIsPressed){ x = lerp(x,mouseX,0.1) y = lerp(y,mouseY,0.1) } // line(0,0,px,py) // line(0,0,x,y) // // fill(255) // text(sec,x+random(-50,50),y) // let ll = dist(mouseX,mouseY,pmouseX,pmouseY) // stroke(255,map(ll,0,100,0,255,true)*2) // line(pmouseX,pmouseY,mouseX,mouseY) // strokeWeight(1) // // stroke(0) // line(x,y,mouseX,mouseY) // line(x,y,pmouseX,pmouseY) // ellipse(mouseX, mouseY, 20, 20); } ``` --- ### [彈跳球球](https://openprocessing.org/sketch/883254) 透過球球當前位置計算下個位置,也讓滑鼠的位置參與互動,點擊的話會讓球的位置逼近滑鼠,最後加上超過畫面底部的話動量反向的設定,讓球有種彈跳的感覺。 ![](https://i.imgur.com/DY73OnM.gif) ```javascript= function setup() { createCanvas(windowWidth, windowHeight); background(0); stroke(0) strokeWeight(2) x=0 y=height/2 // strokeWeight(0.1) } // var number = 1 var x = 0 var y = 0 var r = 30 var vy = 0 var sec = 0 function draw() { // background(0,5) // print(number) //--------- px=x py=y x=x+2 y=y+vy vy=vy+0.5 if (y>height){ vy=-vy } //--------- x+=random(-5,5) y+=random(-5,5) // if (second()!=sec){ // sec=second() // x=random(width) // y=random(height) // r=random(50) // } fill(map(y,0,height,0,255),map(x,0,width,0,255) ,50) ellipse(x,y,r,r) // stroke(255) r+=random(-5,5) line(x,y,px,py) if (mouseIsPressed){ x = lerp(x,mouseX,0.1) y = lerp(y,mouseY,0.1) } // line(0,0,px,py) // line(0,0,x,y) // // fill(255) // text(sec,x+random(-50,50),y) // let ll = dist(mouseX,mouseY,pmouseX,pmouseY) // stroke(255,map(ll,0,100,0,255,true)*2) // line(pmouseX,pmouseY,mouseX,mouseY) // strokeWeight(1) // // stroke(0) // line(x,y,mouseX,mouseY) // line(x,y,pmouseX,pmouseY) // ellipse(mouseX, mouseY, 20, 20); } ``` --- ### [彩色磚牆](https://openprocessing.org/sketch/883263) 使用使用變數判斷目前 x 的位置,如果超出寬度的話就換行,另外使用 random() 增加色塊的寬度與顏色的多樣性。 ![](https://i.imgur.com/nhkU8tS.gif) ```javascript= var x,y function setup() { createCanvas(windowWidth, windowHeight); background(0); x=20 y=20 } function draw() { let ww = random(100) fill(random(255),random(50)+150,random(50)+100) noStroke() rect(x,y,ww,12) x+=ww+5 if (x>width/2){ x=0 y+=20 } // ellipse(mouseX, mouseY, 20, 20); } ``` --- ### 模擬時鐘 透過 p5 內建方法拿到當前的時分秒,再用 map() 把時間對應到可以用在 arc() 上面的弧度,是很好用的技巧! ![](https://i.imgur.com/TSpd9Qi.gif) ```javascript= function setup() { createCanvas(windowWidth, windowHeight); background(100); } var ang =0 function draw() { background(0) // var ang = map(mouseX,0,width,0,PI*2,true) var s = second(); var m = minute() var h = hour() var angleS = map(s,0,60,0,PI*2) var angleM = map(m,0,60,0,PI*2) var angleH = map(h,0,12,0,PI*2) fill('red') arc(width/2, height/2, 200, 200, 0, angleS, PIE); fill('yellow') arc(width/2, height/2, 100, 100, 0, angleM, PIE); fill('white') arc(width/2, height/2, 50, 50, 0, angleH, PIE); } ``` --- --- ## 內容回顧 ### 變數入門 * 變數的宣告語法: var 變數的名稱 = 變數的內容 * 變數可以裝什麼? 最基本的資料型態有 數字、字串與 boolean 值等等 * 變數的命名方式與習慣:駝峰式命名 ### p5 好用的函式與方法 #### 數值操作: * map():將某個區間的數值對映到另ㄧ個區間 * lerp():在兩個值之間依特定比例取值(線性插值) * random():隨機取值 #### 形狀: * arc():繪製扇形 #### 時間: * hour():取得當前時 * minute():取得當前分 * second():取得當前秒 #### 其他 * 賦值運算符(assignment operator):把原先變數 x 的值經過某個運算另一個值 y 之後,賦值給 x。如 x+=1 的計算結果會等同於 x = x+1,等號前可以放入任意的運算,例如 x *= 2 的計算結果會等同於 x = x*2。 * CSS 色彩名稱:可以直接填入 fill() 函式的顏色字串值,例如 'yellow', 'red', 'cornflowerblue' 之類。可以點這邊看可以用的顏色。 #### 數值的運算與處理: * %:讀作 mod,用來取餘數。例如 16%3 => 1 * abs():取絕對值。例如 abs(-4) => 4 * floor():取「地板」,即為「無條件捨去」。例如floor(1.4) => 1 * ceil():取「天花板」,即為「無條件進位」。例如ceil(1.4) => 2 * +,-,*,/ :分別為加減乘除 ## 五、課後問題 ### 變數是什麼?我們為什麼要使用變數? 除了提到的三種類型(數字、字串、boolean),JavaScript 這個程式語言還有哪些資料型態呢? ## 六、作業方向 創造你的時間表達方式:除了時鐘之外,還有哪些元素與型態可以作為表達時間的方式呢?水的流動、星辰的轉動或是張眼閉眼都可以是時間走動的象徵,活用 p5 的時間函數與 map() 應對,呈現ㄧ個屬於你的時間表達吧! --- --- --- 創作概念 連結 軌跡 狀態 - 觀摩 - ![](https://i.imgur.com/kPizGrV.png) - https://www.openprocessing.org/sketch/763615 - https://www.pinterest.com/pin/125608277095922192/ - https://www.pinterest.com/search/pins/?q=generative%20art&rs=typed&term_meta[]=generative%7Ctyped&term_meta[]=art%7Ctyped - 物理模擬 - 粒子 - 變數 - 減少重複 - 暫存手邊需要的資料 - 做複雜的運算時解構概念 - 留下上一刻的狀態 - 賦予數值與資料意義 - 類型 - 數字 - 字串 - true/false - p5.js的系統變數 滑鼠、鍵盤 - mouseX / mouseY / pmouseX / pmouseY - mouseIsPressed - keyPressed - mousePressed - LEFT_ARROW - RIGHT_ARROW - UP_ARROW - DOWN_ARROW - SPACE - https://p5js.org/reference/#/p5/keyCode - 數字的操作 - % 取得餘數 - abs - floor - +-*/ - 變數命名的規則 - Camel Size - 轉換數值的範圍應用 - map / constrain - lerp 逼近 - min / max - 繪製圖形進階 PIZZA - arc - curve - 亂數的應用 - random(最小,最大) - random(陣列) - 時間 * day() * hour() * minute() * millis() * month() * second() * year() - 繪製時間表達的函數 - 範例:球球物理 ![](https://i.imgur.com/DKoFFke.png) https://www.openprocessing.org/sketch/883254 ![](https://i.imgur.com/GEjkLpw.png) https://www.openprocessing.org/sketch/883263 稍微修改、調整細節後可以延伸成這樣 ![](https://i.imgur.com/XR7F2cj.png) https://www.openprocessing.org/sketch/884104 - 課後練習? - ---