CreativeCoding 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/tag/creativecoding/ 蒐集互動設計案例、教學與業界資源,幫助你一起進入互動程式創作的產業 Wed, 05 Jul 2023 04:45:43 +0000 zh-TW hourly 1 https://wordpress.org/?v=6.2.2 https://creativecoding.in/wp-content/uploads/2022/03/cropped-cct-logo-icon-2-32x32.png CreativeCoding 彙整 | Creative Coding TW - 互動程式創作台灣站 https://creativecoding.in/tag/creativecoding/ 32 32 CC!我跟你說!S1EP1|理工宅的藝術創作之路:國內外程式創作、互動藝術進修資源,以及老闆的建議 https://creativecoding.in/2023/05/17/podcast-s1ep1/ Wed, 17 May 2023 08:18:14 +0000 https://creativecoding.in/?p=3767 在本集中,我們將探索 Creative Coding 的奧秘——里歐娜會和老闆一起討論什麼是 Creative Coding ,以及老闆是如何踏上這條路的,在這條路上,又遇到了什麼樣的困難和驚喜之事呢?我們還會分享一些有趣的案例,並且比較台灣與國外的程式創作資源的不同之處。如果你曾經對學習程式的門檻感到困惑,相信本集也會對你有所啟發。

這篇文章 CC!我跟你說!S1EP1|理工宅的藝術創作之路:國內外程式創作、互動藝術進修資源,以及老闆的建議 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>

在本集中,我們將探索 Creative Coding 的奧秘——里歐娜會和老闆一起討論什麼是 Creative Coding ,以及老闆是如何踏上這條路的,在這條路上,又遇到了什麼樣的困難和驚喜之事呢?我們還會分享一些有趣的案例,並且比較台灣與國外的程式創作資源的不同之處。

如果你曾經對學習程式的門檻感到困惑,相信本集也會對你有所啟發。最後,我們也會分享近期 Creative Coding 相關的活動資訊!

至以下平台收聽: FirstStory / Spotify / KKBOX / Pocket Casts / Apple / Google / SoundOn

老闆小檔案

老闆哲宇是互動設計師,也是數位藝術家、講師、全端工程師。先前在紐約大學進修整合數位媒體碩士,在 Creative Coding 領域有相當厲害的創作專業,知名 NFT 作品包含 Pochi 、 Hamily 家族等。

哲宇在教學推廣上也不遺餘力,引領超過 20,000 位學生進入互動網頁與生成藝術開發的大坑。在文化推廣上,他成立了 FAB DAO ,希望能提攜台灣數位藝術家,被世界看見,期望可以帶著更多人,在數位世界中創造驚喜的體驗與生命。

精選片段

老闆的大學回憶:在學聯會行銷部,用 Arduino 做了蝦趴聖誕樹,還在 Dcard 上爆紅?

本集重點 ⬢

02:21 究竟什麼是Creative Coding?

03:31 老闆開始接觸Creativ e Coding的契機

05:17 Creative Coding的有趣案例

08:28 藏在非典型電機人內心的創作熱血🔥

09:39 出國進修的動機💭、國外程式創作與教育環境

15:59 我們都有茫然的時期…

18:16 國外的程式創作資源、互動設計風氣和台灣有什麼不同?

21:31 面對學習程式的門檻,我該怎麼辦——身為過來人,老闆用心良苦的建議

30:44 在台灣的進修資源有哪些

32:20 學習Creative Coding有什麼出路或運用?

36:36 老闆語重心長的建議

38:09 近期Creative Coding相關活動資訊

如果有任何的意見回饋或建議,歡迎來信讓我們知道,各位的參與是我們進步的動力。讓我們一起朝向更好的 Podcast 節目邁進吧!

⌔ 寫信給我們:creativecoding@monoame.com

這篇文章 CC!我跟你說!S1EP1|理工宅的藝術創作之路:國內外程式創作、互動藝術進修資源,以及老闆的建議 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座 https://creativecoding.in/2022/10/24/generative-art-basic/ Mon, 24 Oct 2022 03:16:34 +0000 https://creativecoding.in/?p=3001 對科技藝術總是抱著忐忑不安的心情,以至於還不敢踏進來嗎?本篇藉由科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座直播影片內容作撰寫,藉由跨領域分享與實作教學,讓你跟我們一起安心入門。

這篇文章 科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
對科技藝術總是抱著忐忑不安的心情,以至於還不敢踏進來嗎?本篇整理自科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座直播影片,應 ITSA – 教育部智慧創新跨域人才培育計畫的邀請,老闆以新媒體藝術家的角度,分享目前程式藝術界的發展脈絡和創作入門,也藉此引領有興趣的同學們入門。上半場以科技藝術 Creative Coding 做開場介紹,適合初學者快速通盤了解科技藝術目前在市場上面的應用,以及如何使用如 MaxMsp 或是 p5.js 等現有工具進行創作連結,將基本程式使用延伸到創作。下半場以 p5.js和 MaxMsp 的介紹與創作教學為主軸,包括如何應用與未來趨勢分享,如果想要了解更詳細的創作撇步,歡迎至老闆的互動程式藝術創作課程喔!

科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座

什麼是 Creative Coding?

通常大家比較常將 Coding 認知為解決問題的一種工具,以比較制式的方式去解決設定好的問題。而 Creative Coding 在新媒體藝術領域來說,是結合設計、工程、數學、動態、程式邏輯與硬體的一種創作形式,嘗試在不同事物間建造一座溝通的橋樑。只要擁有程式的基礎概念、能夠靈活運用以及美感具備,就能創作出有趣的作品。以池田亮司,這位來自日本的聲音和視覺新媒體藝術家舉例,其藝術創作多是以資料轉化為視覺藝術模式進行,並投射在物件上,使觀眾在進入藝術展間時,有種身處異空間的錯視感;或是知名沉浸式內容製作公司 TeamLab,以商業型展覽為主,藉由展品與觀眾間的互動模式呈現作品;除了在展覽上的呈現外,像是演唱會或是公共裝置藝術也是現今常被應用的管道。

「Floating in the sky – VR experience」- 吳哲宇(取自吳哲宇個人網站

老闆以「Floating in the sky – VR experience」介紹其創作理念,藉由個人的想法作為出發點,使用了 UNREAL 遊戲引擎、MaxMsp和自行製作的音樂, 結合軟體與硬體間的互動所呈現的有趣 VR實境作品。還有像是「Net Device – The Gambling Lamp」及「Explode – Motion Capture Performance」這幾項作品,帶出不同事物之間,皆能以程式來進行對話,甚至最終變成視覺化的藝術創作。

Creative Coding 對概念的視覺化,強調用不同領域及不同的觀點將自身的角度陳述出來,像詩意運算就是早期在做 Creative Coding 的藝術家所提出來的概念,藉由程式撰寫所表現出的質感、顏色或是律動的模式,如 Tyler Hobbs高偉俊介 或是 Matt Deslauriers,這些具有燈光藝術與裝置藝術背景的創作者作品,在與藝術創作時所提到的「心流」有極大的相似之處。

現在 Creative Coding 最主要的發展方向強調的是,所有人皆能上手的程式語言撰寫,建立現有的程式資料庫,讓沒有程式背景的人在有足夠認知的能力下,也能快速反應的應用方式。而在創作時還是建議,作品本身觀看時,可以不用解釋也能理解其想表達的事物。

從網頁教學到 Creative Coding 教學

HaHow好學校的網頁設計課程
〈動畫互動網頁程式入門 (HTML / CSS / JS)〉
HaHow好學校的網頁設計課程
〈動畫互動網頁程式入門 (HTML / CSS / JS)〉

最初,老闆是以視覺平面設計師的角度教授動畫互動網頁程式入門 (HTML/CSS/JS),在課程中使用 Codepen 或是 OpenProcessing,希望引導設計師們不只是使用程式,更希望能創造出想要的網頁視覺樣貌。以 Vue.js 舉例,一般具工程背景的同學大部分拿它做出網頁的資料框架,但老闆將其應用,做出互動式網頁鋼琴作品

為了將互動式網頁進階與特效做結合,老闆開設了第二門課程,動畫互動網頁特效入門(JS/CANVAS)。在網頁設計的教學歷程中,發現從顏色、平面設計或是為了動態設計而應用到的三角函數等數學(延伸閱讀 : 來用可怕的三角函數做網頁吧! -Part 2科幻時鐘(直播筆記)),這些其實也都是 Creative Coding 應用內容。

其實,使用 Coding 的邏輯也能套用在不同的傳統藝術作品上,舉例來說,許多印象派的畫作皆由不同的筆觸重複堆疊而成,而 Creative Coding 也能使用相同的概念去創作,再應不同的創作設計出不同想法,將客觀物體經由本身的主觀認知詮釋成新的作品。也因此開設了第三門〈互動藝術程式創作入門 (Creative Coding)〉,使作品不限於視覺、聲音、投影或裝置藝術等等,是跨足所有互動相關開發的核心概念。(延伸閱讀 : 章節一 Creative Coding程式創作是甚麼

目前老闆仍持續應用 p5.js 和  OpenProcessing 做創作及教學,前期也有在 C-LAB 工作坊作做分享(延伸閱讀:創意程式設計:Processing/p5.js教學與趨勢觀察——王連晟、吳哲宇台美連線對談)。

p5.js網站首頁(取自p5.js網站首頁)

p5.js 的由來是一位在紐約新媒體藝術家, Lauren Lee McCarthy 所建立的,將開源式語言 Processing 以 Javascript 語言做應用,只要能夠跑瀏覽器就能創作,像是現今流行的 Sketch 和 Figma 等設計工具,就是應用了瀏覽器虛擬化的特點,不用再多安裝任何軟體,在網頁上即可進行。而 p5.js 也藉由其免費及開放資料庫的特性,降低了學習門檻,吸引更多人進入 Creative Coding 的領域。

在上半場的分享中有許多踴躍發言,以下為紀錄同學與老闆的問答:

Q:如何在實作上使用 UNREAL,操作以上所提到的效果並搭配音樂?
A:可以在每節旋律上擷取重拍的位置做效果,或是依據旋律的大小聲做變化。

Q:如何調適創作時的低潮?
A:在創作時必然有自己或他人不喜歡的作品,但還是鼓勵可以從每一次不同的產出中獲得不同的養分,變成下一個的創作靈感。老闆提供自身經驗說到創作的想法來自將日常所發生的點滴記錄下來,或者是平日感興趣的問題也能作為深入探討的目標。

Q:如何使用硬體 EYESY 來做生成式藝術?
A:藉由音樂的輸入,與程式的應用,傳導出生成式藝術。

接續上半場的應用介紹,下半場老闆二話不說實際展示了 Live coding 線上 Demo 給同學們。

p5.js 線上 Demo

本次 Demo 為介紹基礎應用,以下介紹會使用到的 API 及創作成果,使用 Openprocessing 做撰寫,各位直接點擊連結便能開始創作。

應用 API 介紹

  • createCanvas(width, height):創建畫布,參數中分別輸入寬跟高的大小。
  • background(colorCode):制定背景色,可依照文件輸入色碼參數或是基本顏色英文名稱。
  • ellipse(x, y, width, height):在 (x, y) 上繪製一個寬高 (width, height) 的橢圓形。
  • circle(x,y,d):在 (x, y) 上繪製 d 大小的圓形。
  • mouseX():滑鼠沿著左右移動。
  • mouseY():滑鼠沿著上下移動。
  • frameCount():控制每一秒產生的 frame 格數。
  • random():亂數,沒有傳參數時,會來回的隨機浮點數。
  • fill():填入圖形顏色,依照 colorMode 選擇的填色模式填入對應的參數。
  • stroke():圖形邊框顏色,依照 colorMode 選擇的填色模式填入對應的參數。
  • strokeWeight():邊框粗細,依照填入的數字大小。
  • if-else:判斷多種不同條件執行。

基本程式裡分成兩個部分,setup 與 draw。前者代表在畫布上的設定,後者代表不斷在畫布上重複著畫上新東西的動作。而 function 則是指動作的集合。以下先依序講解如何應用基本 API 設定。

一、背景顏色置換示範
function setup() {
  createCanvas(windowWidth, windowHeight);
  background(100); //色碼
}

function setup() {
  createCanvas(windowWidth, windowHeight);
  background("red"); //顏色名稱
}

第一步,先建置畫布,設定畫布的大小及顏色。尺寸使用 createCanvas(width, height) 在參數中分別輸入寬跟高的大小。而畫布顏色使用 background(),並在括號裡依照文件填入色碼(上)或是基本顏色名稱(下)。

二、繪製圖形、圖形大小與顏色變更示範
function draw() {
  fill('black')
  if(mouseIsPressed){
    fill('red')
  }
  stroke('white')
  strokeWeight(2)
  circle(mouseX,mouseY,mouseX+random(50))
}

第二步,畫布上的圖形建置。圓形隨著滑鼠的位置出現,大小會隨著滑鼠在 X 軸上的移動加上到50間的亂數做變化,圓形外框為白色的並且粗細設定為2。在按下滑鼠鍵時,圓形將會被填上紅色,如沒有便是黑色。

三、示範成果
function setup() {
  createCanvas(windowWidth, windowHeight);
  background('black');
}

function draw() {
  fill('black');

  if(random()<0.2){
    fill('white')
  }

  if(mouseIsPressed){
    fill('red')
  }

  stroke('white')
  strokeWeight(2)
  rect(mouseX,mouseY,mouseX/2+random(50))}
}

在這邊,我們先設置一個與視窗長寬相符的黑色畫布,並且在上方生成在不同情況下會有不同外觀改變的長方形,正常情況下,為黑色方形,外框為白色的並且粗細設定為2,而大小會隨著滑鼠在 X 軸上的移動除以2加上到50間的亂數做變化。在亂數小於0.2時,就會變換為白色方形,當按下滑鼠鍵時,則會是紅色方形。將上述 API 整合使用,便會出現以下的Demo範例。

Demo

應用以上基本教學,加上自己思索想要的圖樣,開始小試身手看看!

什麼是 MaxMsp?

MaxMsp 網站首頁(取自 MaxMsp 網站首頁)

MaxMsp 本身具有程式語言的概念,以 Creative Coding 應用在音樂的視覺化效果呈現。其撰寫與 p5.js 的不同在於,一般會以程式碼顯示,但在 MaxMsp 是直接以視覺的圖案的方式做呈現,將語言命令可視化成一塊一塊的圖形,再依位置的安排去創造不一樣的效果,串接出不同的流程。

MaxMsp 實際應用(截圖自本講座影片)

如何開始撰寫呢?在打開版面後,我們能運用兩側及上下方的按鈕來做指令,或是在空白處左鍵點擊兩下叫出長方形空白格,並在空白格內打入文字指令。

以下為本次示範有使用到之按鈕與指令名稱:

  • delay:接收訊號與要延遲多久,假設在delay處設定1000,等於在觸發第一個動作之後,隔一秒才會觸發接在delay後的動作。
  • cycle:在這邊就代表著數學中三角函數的 sin,代表正弦曲線。
  • toggle:控制物件或是介面的開與關
  • scope:類似於製波器
  • dac:將數位的訊號變成類比的訊號
  • ~ :代表輸出時是類比的訊號,為一連串的音訊作呈現
  • saw:鋸齒波
  • tri:三角波
  • slider:藉由在slider上面的滑動製造出聲音
  • kslider:虛擬鋼琴鍵盤
  • mtof:轉換音符對應到的頻率
  • function:設定 ADSR
  • metro:節拍控制
  • sub patch:子函數
  • midiinfo:可讓 midi 裝置在 Maxmsp 裡呈現
  • polyin:可一次取得多個聲音輸入

如何製造出音符?

藉由訊息傳遞數字的不同,連結上 slider 後,再藉由觸發的時間點差異去形成一顆音符。再音高上面,則可以使用虛擬鋼琴鍵盤 kslider,將鍵盤上的音符轉換成頻率,透過視波器去看再圖形上面的呈現。

對於聲音的控制,最主要的兩點為音高與音量大小,傳統在音樂合成上有 ADSR 作為進行的代表。ADSR 字母分別代表了四個不同意思,分別是Attack 、Decay 、Sustain、Release,中文意思為起音、衰減、延音、釋放。

ADSR 圖像(取自維基百科

起音:從無聲音開始上升到最大音量所用的時間。

衰減:最大音量下降到指定的維持音量所需的時間。

延音:主要聲音持續的時間。

釋放:延音到無聲音所需時間。

經由 function 撰寫 ADSR 後,我們得以此控制音量的大小,再加上節拍的控制及前面的波長頻率設定,就完成了基礎 MaxMsp 範例,將音符呈現。

MaxMsp 實際應用(截圖自本講座影片)

再更進階要取得多個音符一次輸入的話,將上述一個音符所應用到的程式函數化,使用 sub patch 濃縮至一個圖形中。如要外接 MIDI 音樂數位介面,且多個音符同時呈現,只要設置 midiinfo 讓 MIDI 音符輸入,再以 polyin 取得同個模組多個聲音,就能製造出好玩的音樂。老闆也分享自身經驗,在前期街觸到 MaxMsp 的 noise 功能後,發現與節拍還有音符的結合創造出非常有趣的東西,因此也鼓勵同學能多方嘗試,玩出興趣也激盪出不同的火花。

新媒體藝術家與新媒體藝術未來趨勢發展

來到講座的最後,老闆分享對於新媒體藝術的未來觀點,新媒體藝術在之後還是會持續存在,不過重點是應用的軟體或平台可能會有所改變,而身為創作者,我們要如何去融會貫通各種不同的應用,以及背後的創作理念呈現的思考方式,都是可以多加著墨以應變未來變化。

例如,元宇宙,將所有3D物件都無資料庫化,以類區塊鏈的方式,將所有人的東西都在網路世界做一個副本,虛實整合,所以不論是虛擬世界及現實世界都能執行交易。也帶領傳統藝術家經由生成式藝術觸發更多不同的靈感。老闆建議,如果要嘗試開始進入新媒體藝術的同學可以從 p5.js 開始下手,或是經由觀看多位不同新媒體藝術家的作品了解應用。

Q. 數位的東西得以快速實踐以及被改變,何以說明所謂的原創?
A. NFT 其實就是以數位正本的概念去運做的,所有人在網路上的交易紀錄都能被認得與證明,清楚的說明所有權的歸屬,這也才造就價值,以限量性和稀有性。

建議從最終想要達到甚麼樣的目標,去開始思考,能從何種媒材下手運用,再來進入到可以使用哪些資源開始學習與實踐。

結語

看完影片和文章後也對科技藝術躍躍欲試了嗎?加入互動藝術程式創作入門課程開始學習吧!還有不要忘了追蹤老闆 Twitter 和訂閱老闆,來點寇汀吧。Boss, CODING please. Youtube 頻道隨時補充新媒體藝術的養份,讓我們一起探索這多元的世界!

此篇直播筆記由幫手熊柑協助整理

這篇文章 科技藝術初階入門看這篇準沒錯!! 新媒體、科技與程式藝術創作入門講座 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
把程式當畫筆!《互動藝術程式創作入門》學生作品賞析 https://creativecoding.in/2022/02/08/creative-coding-students-artworks/ Tue, 08 Feb 2022 01:58:00 +0000 https://creativecoding.in/?p=1647 在創作的道路上我們難免會遇到卡關的時候,這次帶大家欣賞互動藝術程式創作入門課程中同學們的作品,看完別人的創意之後,你是否也躍躍欲試了呢?

這篇文章 把程式當畫筆!《互動藝術程式創作入門》學生作品賞析 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
在創作的道路上我們難免會遇到卡關的時候,腦袋就像打了死結的繩子、一灘死氣沉沉的池子,對於本業也是設計師的Ju編來說,這時候除了從自己的生活中尋找靈感外(a.k.a. 放假),欣賞別人的作品也是一大靈感來源。透過觀察與剖析藝術家們的腦袋,理解作品背後的動機與手法,替自己的創作注入新的活水。

這次要來帶大家欣賞互動藝術程式創作入門課程計畫中,同學們的作品。大家來自不同背景,當中也是不乏沒有程式基礎的同學,但是在完成課程的前五個章節之後,同學們都有能力開始創作屬於自己的程式藝術作品,逐漸實現腦中的創作想法。

《Drain》張晉國

「一張畫面裡的節奏如果是好的,他不管放在哪,都會是好看的。」靈感來源自於將音樂中聽覺上的「節奏」本身,透過生成式藝術轉換成視覺上的「節奏」,製造一種「用眼睛聽」的畫面。作品以聲音和粒子之間的互動形式為主軸,但在製作的過程中對於如何建立視覺和聽覺的同步性遇到了些許困難,所以轉而呈現出類似音樂播放器的效果,將粒子的移動速度、變化型態和聲音大小做互動,交織出宇宙中的夢幻感。

《Drain》作品截圖(藝術家:張晉國)
《Drain》作品截圖(藝術家:張晉國)

作品線上看

判斷聲音大小的區間可以使用函式getLevel(),設定如果聲音超過某個區間,粒子的數量就會大量增加,同時也會加入半徑較大的粒子。

哲宇老師點評:
如果有意願嘗試這種音樂節奏性的東西的話,可以先嘗試使用音量來觸發拍點,或是使用主要聲音的頻段來觸發視覺效果,以某段頻譜的平均波幅作為觸發的依據,產生粒子、改變顏色,會比較容易製作。

《Houses》蔡明達

以藝術家本身的職業為出發點,營造一個又一個的溫馨個人小空間,呈現出各種傢俱、窗戶的室內擺設排列組合,透過滑鼠的移動連動白天夜晚交替的變化,同時房子和傢俱也會根據光源而有不同的顏色變化。喜歡的話心動不如馬上行動,不然一下子就Sold Out囉!

《Houses》作品截圖(藝術家:蔡明達)

作品線上看

哲宇老師點評:
P5.js裡面有基礎的3D盒子 box() 和 光源 pointLight() 可以運用,可以變化試玩看看。

《Shadow》黃亦涵

最初創作的靈感來自於俄羅斯構成主義,交錯的矩形為特色,除了製作出塊狀的建物效果外再加以光影變化,運用明暗交錯轉換,營造出時間竄動的感覺。重複的元素以及簡單的構成,讓畫面產生韻律的疊加。

《Shadow》作品截圖(藝術家:黃亦涵)
《Shadow》作品截圖(藝術家:黃亦涵)

作品線上看

哲宇老師點評:
在處理這種比較複雜的陰影層次時,可以先把影子畫在一個圖層上,再用疊合模式畫在其他圖層上方。如果想要在光影或建築的傾斜程度做互動效果,可以使用shearX()控制平面或物件的傾斜程度,比如在畫物件前可以把整張畫面傾斜。

《章魚噴噴墨》陳慧珊

對於藝術家來說海洋是個讓人想起來就很放鬆的地方,作品以廣闊的海底和悠遊的魚群為背景,可愛的章魚先生為主角。把每天遇到大大小小、多到吐不完的煩悶事情,藉由滑鼠按壓章魚先生,一起隨著墨汁吐出去吧!

《章魚噴噴墨》作品截圖(藝術家:陳慧珊)
《章魚噴噴墨》作品截圖(藝術家:陳慧珊)

作品線上看

哲宇老師點評:
在製作的途中遇到圖層分層的小小困難,主要是章魚和魚群的繪畫順序需要調整一下,越上面的圖層會越後面繪製,image()應該是最後畫上去的。
也可以試試看墨水在水中暈開、越來越稀釋顏色漸淡的效果,每畫一次墨水就先疊上一層白色背景,再push()用blendMode(MULTIPLY)渲染,要讓他變淡等於讓他變白 inkGraphics.fill(255,10),有一定的透明度後把整個畫面再蓋一次白色inkGraphics.rect(0, 0, witdth, height),就可以製造漸淡的效果。
這邊提供一些不同的手法來增加畫面的層次感,比如:將魚分成兩層疊加,或者給魚一些不同的顏色或造型,如果想要製造接近魚群時魚群會閃避的效果,可以給予一些隨機的速度或向量。

《水墨漣漪》林文聖

藝術家本身是財金系畢業,在一次擔任志工的機緣下對設計產生興趣,再進修文創和平面設計相關的學程後,轉往前端的方向發展。

因為OpenProcessing上的東方元素作品較少,便嘗試從水墨畫發想。靈感來自於《時間之花》李炳曄,一開始想嘗試將時間和作品產生連結,但概念比較複雜所以改嘗試與水做互動。
當墨水滴入水中產生一圈一圈的漣漪,顏色也隨之在水中暈染且逐漸稀釋。作品使用鏡像疊加呈現,讓視覺有規律得變化,在墨水也會隨著滑鼠的位置以同心圓的方式改變,交互的作用下,形成如萬花筒的世界。

水波紋的效果:將物件的像素放大、frame調低,製造遞延的效果。例:pixelDensity(1/7)

《水墨漣漪》作品截圖(藝術家:林文聖)
《水墨漣漪》作品截圖(藝術家:林文聖)

作品線上看

哲宇老師點評:
如果要把波紋做得更細緻(波紋之間的干涉),可以用shader下去做。使用Shader的GPU是一點一點下去計算的,可以控制每個像素是疊合什麼顏色,這種更細緻的控制。
如果要在p5.js做,可能就要考慮像素等級的疊合,比如兩個source最靠近的那一條會受到影響的重疊範圍,各自再往原本的source偏移一些,有點像會變成被壓扁一側的圓型。

《Mysterious Bomb》Athem Lin

藝術家本身是YouTuber老高以及特斯拉的粉絲,對於像宇宙、亞特蘭提斯、外星人等等的概念很有興趣,進而創作了這個作品。

可以透過滑鼠切換作品中的兩個模式:原子爆炸、夢幻方塊,在點擊時會有爆炸後收縮的效果帶你進到另一個宇宙。

在創作過程中遇到的困難是,有時好不容易想出一個作品的方向,但從理想到實作又是一趟漫長的過程,不見得每次都能夠實現。這時會去參考其他藝術家的表現手法,藉由觀摩來摸索出屬於自己的方法。

《Mysterious Bomb》作品截圖(藝術家:Athem Lin)
《Mysterious Bomb》作品截圖(藝術家:Athem Lin)

作品線上看

哲宇老師點評:
作品從元素呈現到音效選擇都很到位,完整度很高。一般剛踏入Creative Coding的世界時,大部分都是觀摩作品然後做修改,但這個作品很有個人特色,有呈現出藝術家的風格。

《Universe》孫宇

遼闊黑暗的宇宙中,偶有光亮。就像人生失落寂寞中,偶有希望。希望這些希望可以多一點,帶給身邊的人,成就更美好的自己。

《Universe》作品截圖(藝術家:孫宇)
《Universe》作品截圖(藝術家:孫宇)

作品線上看

哲宇老師點評:
作品比較偏粒子疊加的嘗試,有用blendMode()去做疊加,更進階一點可以在形狀旁邊加光暈。

drawingContect.shadowColor = color(255,100)
drawingContect.shadowBlur = 10

以上就是這次的分享,希望透過觀摩別人的作品可以帶給大家一些新的創作靈感,那麼我們下次再見啦👋👋👋

看到這裡,你對 Creative Coding 更有興趣了嗎?
歡迎加入互動藝術程式創作入門(Creative Coding)線上課程,課程中你可以認識程式與互動藝術產業應用,開啟對工程跟設計的想像,學會使用 p5.js 開發互動介面,整合繪圖、音訊、視訊、文字、3D、互動與機器創作完整的作品,並將創作輸出應用在個人品牌或網站、主視覺或海報,甚至互動裝置、遊戲與教材製作等場景,讓你對進修的資源與路線更有方向。

此篇直播筆記由幫手 Jeudi Kuo 協助整理

墨雨設計banner

這篇文章 把程式當畫筆!《互動藝術程式創作入門》學生作品賞析 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
【p5.js創作教學】CreativeCoding 花火大會(直播筆記) https://creativecoding.in/2021/09/16/p5-js-creativecoding%e8%8a%b1%e7%81%ab%e5%a4%a7%e6%9c%83/ Thu, 16 Sep 2021 03:08:00 +0000 https://creativecoding.in/?p=1430 為響應日本的一群Creative Coder在Processing Community Day的社群串聯,扮起虛擬的花火大會,我們也來利用p5.js,結合粒子系統、漸變顏色甚至是聲控模組,一起在夜空中創作出絢麗的煙火吧!

這篇文章 【p5.js創作教學】CreativeCoding 花火大會(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
說到夏天,就想到海邊;說到海邊,就想到日劇裡的西瓜跟煙火。一束束的煙火短暫但繽紛,燃燒自己的生命點燃絢麗的光譜,珍惜每次綻放都是不同的樣貌。最近(2021年8月)有一群日本Creative Coder在Processing Community Day時串連起社群,在Twitter上辦起虛擬的花火大會,透過各自的作品在版面上綻放了大大小小的煙火,替最近被疫情拉開實體距離的生活中,增添一些夏天的顏色。

讓我們抓住夏天的尾巴,一起用粒子系統與漸變顏色創作煙火吧 🎆

今天要使用的是OpenProcessing搭配p5.js函式庫的大禮包組合,如果對這兩個工具還不太熟悉在這篇文章可以看到更多介紹 👉🏻 p5.js 快速上手

讓我們用草稿規劃一下煙火的概念,如果要做以粒子為基礎、從中心炸開的煙火,應該是一顆粒子從畫面水平線的底部往上移動特定距離,在上方炸開很多不同的粒子、且粒子各自擁有不同的運動方向。

根據以上的概念,我們今天會切分為以下步驟來進行:

  1. 粒子系統
  2. 動態延伸(移動、爆炸分裂)
  3. 顏色變換
花火大會作品草稿示意圖
花火大會作品草稿示意圖

製作粒子系統

首先第一個步驟我們先完成煙火的核心——粒子系統,以單顆粒子的物理模型來說會有位置(P)、速度(V)、加速度(a)和顏色(Color)、大小(r)等變數。在OpenProcessing先把畫布設成1000×1000、黑色的夜空之後,另外新增一個Tab,用來放置我的們的Class particle,在初始化時我們希望引入一些變數args裡面帶入一些固定的參數做使用,如果使用者有特別設定,把使用者引入的參數args蓋到預設值def上,再把客製化後的設定值蓋到這個物件本體this上。

//Tab2
class Particle {
  constructor(args){
    let def = {
      p: createVector(0,0), //位置
      v: createVector(0,0), //速度
      a: createVector(0,0), //加速度
      color: color('red'), //顏色
      r: 10, //大小、半徑
    }
    Object.assign(def,args)
    Object.assign(this,def)
  }
}

接下來介紹兩個關鍵的method分別是draw()update(),分別負責顯示和更新,切分成兩個部分是為了在更新的時後不動到最初始的顯示,把邏輯層區分出來,這樣對模組化的製作與管理也比較容易。

在同一個 tab2,先來處理draw()push()會保留目前的drawing style、而pop()則會回復這些設定,兩個必須搭配使用。假設粒子移動到this.p位置、顏色this.color、尺寸是this.r

class Particle{
  ...
  draw(){
    //顯示
    push()
      noStroke()
      translate(this.p) //processing可以只給向量,不一定要x,y
      fill(this.color)
      circle(0,0,this.r)
    pop()
  }
  update(){
    //資料更新
  }
}

在主要的程式定義一個陣列particles把粒子都裝進去,我們來初始化一顆粒子試試看,讓objParticle根據剛剛的規範來製作,放在外面並用let比較不會有全域打架的問題objParticle = new Particle() ,成像的位置在畫布寬高一半處,這時在畫布中間就可以看到我們千辛萬苦的第一顆隨機色粒子啦。

let particles = []
let objParticle 
function setup() {
  createCanvas(1000, 1000);
  background(0);
  objParticle = new Particle({
    p: createVector(width/2,height/2),
    r: 100,
    color: color(random(255),random(255),random(255))
  })
}

function draw() {
  objParticle.update()
  objParticle.draw()
}
萬事起頭難,頭過身就過,黑夜中的一顆小紅點。
萬事起頭難,頭過身就過,黑夜中的一顆小紅點。

單一粒子動態軌跡

update()處理位置(P)、速度(V)、加速度(a)和大小(r)的變化,每一顆的位置都會加上速度、而速度都會加上加速度。

update(){
  //資料更新
  this.p.add(this.v)
  this.v.add(this.a)
  this.r*=0.993 //由大變小
}

有物理模型後,我們來處理速度(v)和加速度(a),這邊介紹一個函式random2D(),可以在vector上隨機產生一個2D的向量。套用到速度上隨機產生方向,在爆炸初始時粒子會往原先的方向衝再往下掉,乘5倍讓初始速度>加速度,設定加速度為0.1,這樣我們就得到單一粒子的運動軌跡,也就是煙火炸開時的單一根花瓣。

單獨一顆的粒子運動軌跡。
單獨一顆的粒子運動軌跡。

製作束狀粒子群

在陣列內紀錄產生的粒子,先draw完後再update產生動態。
在陣列內紀錄產生的粒子,先draw完後再update產生動態。

有了一個粒子後,我們可以來做一束的煙火,用這些粒子加起來做成陣列。我們先把objParticle拿進來,用for迴圈做出50個粒子objParticle,再push到陣列particles內。在draw的地方把清單一個一個抓出來,我們就得到初步的美麗煙火了。

let particles = []
 
function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0) 
  rect(0,0,width,height)
	
  for(let i=0;i<50;i++){
		
    let objParticle = new Particle({
      p: createVector(width/2,height/2),
      v: p5.Vector.random2D().mult(5),
      a: createVector(0,0.1),
      r: 20,
      color: color(random(255),random(255),random(255))
    })
    particles.push(objParticle)
  }
}

function draw() {
  fill(0,5) //留下煙火軌跡
  rect(0,0,width,height)
  for(let objParticle of particles){
    objParticle.update()
    objParticle.draw()
  }
}
在夜空中綻放的一束煙火,看起來有點像下垂的海葵(?)
在夜空中綻放的一束煙火,看起來有點像下垂的海葵(?)

模組化並自動發射

完成了一束煙火後,我們要接著做此起彼落發射的夏日花火祭,把發射的動作包成一個function firework就可以重複呼叫它。包起來後先在setUp呼叫一次,也可以引入位置參數(p),如果該參數有值就顯示、沒有則出現在畫面中央。接著設定他產生的頻率,每隔100個frame放一次煙火。

大家可以發現我們調高了煙火的數量,從50到100個,在這個情況中為了預防畫面因為生成的東西越來越慢,我們來消除超出畫面的煙火,用filter()留下小於畫面的物件。

仔細觀察煙火的粒子除了大小不同外,每顆的初始速度也不同,如果初始速度相同就會較規則,看起來像下垂的海葵(?),這邊用random()給予任意值處理,煙火的顏色也調整成HSB模式,相較於RGB模式有更彈性的明度暗度可以使用,色調的變數請參考下圖。

我們把HSB色調分為兩個部分:baseHue和Hue。BaseHue為固定的偏移量,hue為根據每個粒子隨機產生出的値。
我們把HSB色調分為兩個部分:baseHue和Hue。BaseHue為固定的偏移量,hue為根據每個粒子隨機產生出的値。
let particles = []

function firework(p){
  push()
	
    let baseHue = random(300)
	
    colorMode(HSB)
    for(let i=0;i<100;i++){
      let hue = random(0,120)
      let objParticle = new Particle({
        p: p || createVector(width/2,height/2), //有位置p時取用p,沒有時就從畫面中央
        v: p5.Vector.random2D().mult(random(1,10)),
        a: createVector(0,0.1),
        r: random(40),
        color: color((baseHue+hue)%360,360,360) //避免>360的數字都是紅色
      })
      particles.push(objParticle)
    }
  pop()
}

function setup() {
  createCanvas(1000, 1000);
  background(100);
  fill(0) 
  rect(0,0,width,height)
  firework()
}

function draw() {
  fill(0,5) //留下煙火軌跡
  rect(0,0,width,height)
  for(let objParticle of particles){
    objParticle.update()
    objParticle.draw()
  }
  if (frameCount%100==0){
    firework()
  }
  particles = particles.filter(obj=>obj.p.y<height) //留下小於畫面的物件
	
  fill(0)
  rect(0,0,100,50)
  //計算畫面中粒子數
  fill(255)
  textSize(20)
  text(particles.length,50,50)
}
調整過後的煙火,終於看起來比較有層次感,不像下垂的海葵了。
調整過後的煙火,終於看起來比較有層次感,不像下垂的海葵了。

基礎版:滑鼠觸發煙火

接下來加入mouse的互動。首先註解掉自動產生的frameCount,每當滑鼠按壓時就在該位置呼叫firework,為了避免重複參數造成順序混亂,在呼叫時把p包成一個物件{p},記得setUp時也要回傳一個空的物件firework({})

這時候會產生一個問題,因為p引入firework被所有的粒子共用,所以有幾顆粒子他就會被update幾次,我們用copy()複製p出來給當下的粒子,避免所有的粒子共用位置。再加入fireRpraticleR等參數做出隨機粒子大小和隨機煙火大小。

function mousePressed(){
  firework({
    p: createVector(mouseX,mouseY),
    fireR: random(1,100), //煙火的大小
    particleR: random(1,10) //粒子的大小
  })
}
function firework({p, fireR, particleR}){
  push()
    let baseHue = random(300)
	
    colorMode(HSB)
    for(let i=0;i<100;i++){
      let hue = random(0,120)
      let objParticle = new Particle({
        p: (p && p.copy()) || createVector(width/2,height/2), //複製新的位置給當下的粒子,讓它重複100遍
        v: p5.Vector.random2D().mult(random(1,fireR || 5)), 
        a: createVector(0,0.1),
        r: particleR || random(40),
        color: color((baseHue+hue)%360,360,360)
      })
      particles.push(objParticle)
    }
  pop()
}
在夜空中用滑鼠點點點,我們就有初階的煙火大會囉
在夜空中用滑鼠點點點,我們就有初階的煙火大會囉~

進階篇:用聲音觸發煙火

做完基礎煙火互動後,如果可以用聲音來觸發煙火那一定很酷,p5.js裡有一些關於「聲音」相關的函式,今天介紹的是Mic Input可以截取電腦麥克風的聲音,我們先開啟p5.sound的library。

開啟p5.sound
開啟p5.sound

套用官方語法在setUp加上input = new p5.AudioIn()開始取用聲音。

let input

function setup() {
  createCanvas(1000,1000);
  background(100);
  fill(0)
  rect(0,0,width,height)
  firework({})
	
  input = new p5.AudioIn()
  input.start()
}

draw()加上觸發條件,如果有聲音,即在畫布上放煙火。這樣我們聲控的煙火大會就大功告成啦!

function draw() {
	
  let volume = input.getLevel()
  let speaking = voulume>0.15
	
  fill(0,8) //留下煙火軌跡
  rect(0,0,width,height)
  for(let objParticle of particles){
    objParticle.update()
    objParticle.draw()
  }
  particles = particles.filter(obj=>obj.p.y<height) //留下小於畫面的物件
	
  fill(0)
  rect(0,0,400,200)
  fill(255)
  textSize(20)
  text(speaking,50,50)
	
  if (speaking){
    firework({
      p: createVector(mouseX,mouseY),
      fireR: random(1,5),
      particleR: random(1,10)
    })
  }
}

小試身手

做完上面的煙火後,這邊提供幾個大家可以繼續嘗試看看的方向,希望大家可以長出各式各樣的煙火,讓夏天的夜晚更為熱鬧!

  • 粒子的顏色漸層
    可以在def的地方新增endColor: color('yellow'),利用lerpColor()這個漸變函式在Update()指定顏色的變化跟階數。
this.color = lerpColor(this.color, this.endColor, 0.05) //每次變換0.05
  • 扭曲的粒子運動軌跡
    在粒子translate的時候如果根據sin/cos偏移,可以做出扭曲的煙火效果會更漂亮。
curve: random(5),
curveFreq: random(2,40),

translate(this.p.x+sin(this.p.y/this.curveFreq)*this.curve,this.p.y+cos(this.p.x/this.curveFreq)*this.curve)⁠
  • 製造煙火的霧氣
    透過在Particle中的draw()增加一些半透明且半徑較大的粒子,來增加模糊的光影。Color先複製一份避免動到原先的設定,用函示setAlpha()製作透明度。
let copyColor = color(this.color.toString())
  copyColor.setAlpha(10)
  for(var i=0;i<100;i+=10){ //重複畫圓形
  fill(copyColor)
  circle(0,0,this.r*i/20) ⁠
}
  • 混合模式
    加入混合效果,blendMode()調整顏色呈現。
push()
  blendMode(SCREEN)
  for(let objParticle of particles){
    objParticle.update()
    objParticle.draw()
  }
pop()
  • 效能處理
    設定當r小於某個半徑時就不顯現,減少效能負擔。
particles = particles.filter(obj=>
            obj.p.y<height &&
            obj.r>0.01
  )

以上就是這次的教學,成品請參考這裡,希望大家還玩得開心,那我們就下次再見啦!

也許你對互動生成式藝術比較有興趣?來看看老闆的《互動藝術程式創作入門》課程,跟著將近兩千位同學一起把程式碼當作畫筆創作,或是先看看這篇文章,欣賞同學們完成的作品吧!

此篇直播筆記由幫手 Jeudi Kuo 協助整理

墨雨設計banner

這篇文章 【p5.js創作教學】CreativeCoding 花火大會(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
在紐約大學讀研當助教的進化日誌 https://creativecoding.in/2021/07/14/%e5%90%b3%e5%93%b2%e5%ae%87-%e5%9c%a8%e7%b4%90%e7%b4%84%e5%a4%a7%e5%ad%b8%e8%ae%80%e7%a0%94%e7%95%b6%e5%8a%a9%e6%95%99%e7%9a%84%e9%80%b2%e5%8c%96%e6%97%a5%e8%aa%8c/ Wed, 14 Jul 2021 02:15:00 +0000 https://creativecoding.in/?p=959 本篇文章寫於2018/12/21,互動藝術家吳哲宇到紐約攻讀研究所時,首年當助教的心路歷程,以文字和讀者分享其中的酸甜苦辣,如何慢慢運用工具、掌握輔導學生的時間及進度安排,達成這一項具有挑戰性的任務,…

這篇文章 在紐約大學讀研當助教的進化日誌 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
本篇文章寫於2018/12/21,互動藝術家吳哲宇到紐約攻讀研究所時,首年當助教的心路歷程,以文字和讀者分享其中的酸甜苦辣,如何慢慢運用工具、掌握輔導學生的時間及進度安排,達成這一項具有挑戰性的任務,也從中找到創作的樂趣與動機。

今年的夏天,我來到了紐約開始我的研究所生涯,唸的是IDM (Integrated Digital Media),剛開學的時候很急著在學校裡面找到工作(因為想要拿SSN就能辦信用卡跟做很多事了),對自己的感覺就像拿到了一個證明,知道自己真的在這裡開始扎根了,這應該算是我第一個受聘的正職,進行得比想像中順利很多,所以趁著在學期結束的一切記憶都還熱騰騰的時候,為各位帶來在紐約當助教的八卦跟到底都在玩些什麼東西。

為什麼要當助教呢?

學期初的時候原本投了學校IT部門UX Designer的工作,沒想到雖然面試很順利,但是卻遲遲沒有消息,完全就是一個被發無聲卡的節奏,同時間又看到系上開始在找研究助理,我就想說,不如兩個都投投看吧!反正原本自己就在做教學相關的工作,如果還能夠順便幫教授做做project應該蠻好玩的。

紐約大學IDM (Integrated Digital Media)的教授
看起來很兇的我的教授

在還沒見到我的教授之前,看網路上的照片快被嚇死,我的教授看起來超兇,感覺剛被放出來(欸,但實際上見到人之後覺得意外地很和善,長得也完全不像照片上那樣。所以跟教授面試的時候,就開了課程的範例跟敘述一下自己在程式方面的經驗,打開codepen炫了炫。

當下有提到如果IT上了的話,我就要毅然決然地拋棄系上來去曼哈頓上班,享受一下在繁華大城市的感覺,因為我們校區在布魯克林,實在是相對比較悠閒跟沒那麼誇張的繁華。

想了一天之後,覺得如果是繼續做設計稿的話好像跟在台灣做的事情沒什麼差別,又很不甘願工作就只是在電腦前做做別人指定的設計稿,所以就直接聯繫教授說我想要這份工作了XD 現在想想好險是做這個決定,開啟了我後面這一串莫名認真(?的助教進化之旅。

在這12週裡做的事情遠超乎自己的預料,雖然大部分是因為不甘心就只坐在那邊給人問問題,所以會自己給自己找事情做。這學期我把系上的助教體制從一開始的毫無規範,到建立了整套運作規則, 預約制、記錄表格、週報、成效分析與怎麼評估跟分配時間,也大幅的增強了自己建立人際關係的能力,跟知道要如何停損每個人花費的時間,陪養了很多的耐心,在看到一臉呆滯沒在思考的學生的時候不會暴怒XD

當助教的照片,左邊是問題學生一號
左邊是問題學生一號

預約制規劃與規則制定

原本助教應該是不用約的,就是挑一張自己覺得愜意的桌子,捧著電腦把office hour 待好待滿,我一開始不知道其實蠻多研究生助理不會把時數做滿,教授還是會給滿20小時的薪水,所以就傻傻的每週排了20小時的助教時間再來崩潰,因為20小時實在太長,只靠乾等人來的話實在是無聊又無法預測到底要怎麼幫那些學生。

Calendly 預約系統
Calendly 預約系統

那時想起了在預約課程討論的時候,有用過一個好像不錯的軟體叫做calendly,於是我第一週閒暇之餘開始研究把助教時間改為預約制並要求至少要提早一天左右預約,就能看到日曆裡面自動隨著預約會冒出應該要出現在學校的時間。

還好一開始有想到預約制,隨著期中期末大家越來越崩潰,老是捧著電腦一個接著一個來,預約制讓我可以名正言順地留足夠的時間給每個人,當然,也會有提早結束的時候,就當做自己偷偷休息的時候,但尤其是外國人,問問題都沒在客氣的,常常雙手一攤就說,我不會做,把事情全部丟給我,如果東西簡單我還會好聲好氣的說你要多嘗試一下,更多是那種複製一堆別人的code來給我看,說我不會改的,整個怒火就會上來叫他回去自己努力一下再過來找助教。

Calendly 會自動同步預約到行事曆上,到期末的時候超瘋狂的助教時間
Calendly 會自動同步預約到行事曆上,到期末的時候超瘋狂的助教時間

地點跟流浪

原本以為我會有一間自己的辦公室,但夢想第一週就破滅了哈哈,我被告知找一個自己喜歡舒適的角落,學生找得到我就好,因此剛開始我待在系館外面,因為沒有固定座位每週都要換位置,兩週之後實在是很抓狂,覺得不能再這樣像是遊牧民族的當助教下去了。後來,我找到了原來系上的研究生有研究室可以用,一用角落的位置之後一試成主顧,又有超高級的外接螢幕可以用,整個超級方便,所以後半學期就定居在這個座位上了。

我超愛這個座位不要跟我搶wwwww
我超愛這個座位不要跟我搶wwwww

助教日誌的誕生

做助教做到後來已經養成了只要有人來問問題,就會直接紀錄下用了多少時間跟問了什麼問題,這樣的習慣也讓我在後續一樣的學生來問問題時,可以直接找到上次的紀錄,快速的掌握他得學習狀況跟弱點在哪,同時也能當作真的有在認真工作的證明給教授看XD 後來有幾個學生連續助教時間回去後都沒有動,隔週預約繼續來找我從上次進度開始也沒有試著搞懂。

週報

在第一個禮拜結束的時候,總覺得結束的很沒有踏實感,意外想到了以前跟朋友聊天時,他說他每個禮拜都要寄一封整理的Email給老闆,報告這週自己做了什麼,或有什麼想法。仔細想像這樣的方式經營真的挺不錯的!

在國外的工作比較自由,我又深切的感受到其實我的教授自己很忙,完全沒有空理我,把輔導學生的工作都丟給我做,所以我就開啟草稿紀錄一下這週我做了些什麼事情,有哪些學生,然後開了一個表格把每個學生問的問題跟我幫忙解決的事情記錄下來,整個學期累積下來真的超級可觀的。

減少資訊不足的情況卡住

一開始填寫預約的時候只有填名字跟問題,直到做了兩週之後,我才發現原來我要負責的不是只有我們教授的班,而是系上這學期所有的班都是我要負責的,而且研究所跟大學部也都是來找我問問題(這堂課給大學部跟研究所的兩個版本)。

難怪每個學生來作業跟課綱都超級不同,發現這件事情的時候,痛苦了好一陣子,覺得自己被推坑做了超雷的工作,但後來整理好心情好之後就想要怎麼樣管理這麼多班級的學生,所以後來我就把預約表單一次問完。

可以非常優秀的管理預約資訊 — Calendly
可以非常優秀的管理預約資訊 — Calendly

有時候助教時間結束後,會需要寄一些參考資源給學生,原本還會很認真的一封一封弄,但是後來數量實在太多懶惰了,就做了一套罐頭信模板,可以直接把名字跟連結填一填複製信件寄出。

罐頭信模板
罐頭信模板

第一次領薪水

在美國第一次領薪水的時候真的很感動,目前大概薪水可以勉強打平房租+生活費,硬是死撐著用著覺雖然大部分都會超過一些些,但是能有能力第一個學期就用專業支撐生活的感覺很棒,雖然跟學費相比真的是杯水車薪,不過就心態而言是告訴了自己,你有在國外好好過自己生活的能力了呢!

第一次領薪水,真的是賺辛苦錢QQQ
真的是賺辛苦錢QQQ

成效分析

最後兩週的時候,因為資料實在太多,一眼看不出到底有多少學生來跟問了多久問題,就又開始自己給自己找事情做,先是把所有學生這學期來的次數列出來,然後統計他們到底都是哪個教授的,有些東西實在是做出來才知道誇張,這學期教授丟了一個網頁小哥來給我,說是他們教授實在幫不了他,所以整個學期他不斷的預約來找我。
做完整理之後,發現這學期總共有四十幾個學生來找我,也發現了很多很常利用助教時間的學生,原來斷斷續續的這樣office hour下來,也真的教過很多次了呢。

來的學生統計圖表,期末跟其中整個大爆炸,也能清楚看見誰是常客

在教學中誕生的眾多範例跟創作

在教學過程中,其實我自己也很常突然冒出意料之外的寫法或創意,就會趕快記錄下來或趁空擋實作出來,在這裡課堂上教的寫程式雖然東西沒有特別難,但是教授都用一種很設計系的方式在帶系上的課,很鼓勵學生冒出很多怪想法,互相討論可以做什麼很ㄎㄧㄤ的東西,和看很多案例,雖然會讓我當助教這邊的loading蠻重的,但能很清楚感覺到跟台灣一般在教程式一板一眼的感覺很不一樣!

圖片像素粒子化
圖片像素粒子化 https://www.openprocessing.org/sketch/627639
3D 球球作品截圖
3D 球球 https://www.openprocessing.org/sketch/635536
有個學生問我要怎麼實作物理引擎,他要做沙畫
有個學生問我要怎麼實作物理引擎,他要做沙畫 (https://www.openprocessing.org/sketch/620161)
北風與太陽作品截圖
北風與太陽 https://www.openprocessing.org/sketch/641437
生成式音樂作品截圖
生成式音樂 https://www.openprocessing.org/sketch/611472
大霹靂作品截圖
大霹靂 https://www.openprocessing.org/sketch/621993
Perlin Noise 地形圖作品截圖
Perlin Noise 地形圖 https://www.openprocessing.org/sketch/619153
訊號處理過程作品截圖
訊號處理過程 https://www.openprocessing.org/sketch/645624
Drawing Machine作品截圖
Drawing Machine (https://www.openprocessing.org/sketch/616561)
科幻感介面作品截圖
科幻感介面 (https://www.openprocessing.org/sketch/598254)
Perlin 雜訊作品截圖
Perlin 雜訊 (https://www.openprocessing.org/sketch/596140)

一些小小心得

能在一個陌生的國度逐漸走穩腳步的感覺很珍貴, 所以自己才會花那麼多的心思在希望把第一份工作做好上,也因為很多來的學生其實是跟自己同一屆的同學,所以有時候助教時間做一做就變得比較熟,能夠有人聊聊天或一起吃個飯,也不會自己一個人悶在家裡做事情,雖然常常以學校為家到半夜兩三點弄完回去,但是過得真的蠻開心的~

對於這份工作心裡還是有些小小的不滿,原本工作描述是說有要幫老師做Project,結果所有時間都被助教佔掉了,教授好像也對我太過放心,所以就也沒什麼管我,每次跟我討論的時候還被說做得太拼了完全沒什麼好挑惕XD

下個學期可能會一起規劃系上的統一課綱的資源庫,也很想把整套學起來自己教哈哈哈,這個學期歷經數百個助教時間摧殘,總覺得已經能夠把整套東西倒著講過一遍了,很希望有一天能把這整套課程帶回台灣,也許能夠為程式教育注入一些活水呢。

撰文:吳哲宇


三門老闆的線上課程,快與上萬名同學一起加入寫code的行列吧!

動畫互動網頁程式入門(HTML/CSS/JS)以簡單例子帶你入門網站的基礎架構及開發,用素材刻出簡單有趣又美觀的網頁和動畫,享受做出獨一無二的網頁所帶來的成就感,在職場上與設計師和工程師合作無間。

打好基本的互動網頁基礎之後,可以進階動畫互動網頁特效入門(JS/CANVAS),紮實掌握JavaScript 程式與動畫基礎以及進階互動,整合應用掌控資料與顯示的Vue.js前端框架,完成具有設計感的互動網站。長達3085分鐘,超過60個精緻範例與400張的投影片以上,以及四個加碼單元vue-cli、GSAP、D3、Three.js的投影片,成為hahow上最長的課程。

互動藝術程式創作入門(Creative Coding)線上課程中你可以認識程式與互動藝術產業應用,開啟對工程跟設計的想像,學會使用 p5.js 開發互動介面,整合繪圖、音訊、視訊、文字、3D、互動與機器創作完整的作品,並將創作輸出應用在個人品牌或網站、主視覺或海報,甚至互動裝置、遊戲與教材製作等場景,讓你對進修的資源與路線更有方向。


你也會有興趣閱讀其他文章:

從不只是一門線上課程,而是一場推動進化的豪賭
釀造一門結合網頁、設計、數學與特效的線上程式課程

墨雨設計banner

這篇文章 在紐約大學讀研當助教的進化日誌 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
用Vue.js做快速換色與整理的便利貼牆吧!(下)(直播筆記) https://creativecoding.in/2021/07/09/%e7%94%a8vue-js%e5%81%9a%e5%bf%ab%e9%80%9f%e6%8f%9b%e8%89%b2%e8%88%87%e6%95%b4%e7%90%86%e7%9a%84%e4%be%bf%e5%88%a9%e8%b2%bc%e7%89%86%e5%90%a7-%e4%b8%8b/ Fri, 09 Jul 2021 02:31:00 +0000 https://creativecoding.in/?p=1178 需要發想靈感、紀錄個人代辦清單,或和他人討論嗎?製作一個能夠自由編輯、增刪、變色、拖曳編排的便利貼牆網頁,多個願望一次滿足。下集將便利貼牆美化、功能變得更完善,更連結firebase即時資料庫,再多張便利貼也不怕。

這篇文章 用Vue.js做快速換色與整理的便利貼牆吧!(下)(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
上一篇我們製作了可以新增、拖曳、換顏色的簡易版本便利貼,這次除了調整細節與動畫外,也會串接Firebase資料庫,讓便利貼牆可以多人同時編輯與更新。

用Vue.js做快速換色與整理的便利貼牆吧!(下)完成圖
用Vue.js做快速換色與整理的便利貼牆吧!(下)完成圖

這次的教學將有以下幾個重點,主要聚焦在既有功能的優化與新功能的添加:

  1. 點擊便利貼文字時因滑鼠與左上角距離設定的關係,會造成距離差而產生的跳動
  2. 加入刪除便利貼的功能
  3. 加入新增或刪除便利貼時,放大縮小的transition
  4. 修改顏色的控制列需和正在使用中的便利貼位置相對應(上次我們處理的方式是都先暫時放在畫面右手邊,這次把它修改得人性化一些)
  5. 編輯文字和多行文字時呈現的大小
  6. 串接Firebase保存資料,即時整理與更新

我們將以Code Pen做為本次實作的平台,這是一個可以在創作的同時即時看到程式碼運作狀況的線上程式碼編輯器,只要簡單註冊就可以使用囉!

如果想搭配直播影片一起實作,請往這邊走

修正點擊便利貼文字造成的距離差

首先fork一份上一次的檔案,fork就像是複製,這樣接續修改也不會動到最初的原始檔唷。

接下來我們在CSS的.postit裡面加上.textpointer-events: none,讓他停止觸發任何的點選事件,在製作滿版圖面但不希望阻礙滑鼠事件時,可以使用這種處理方式(比如:市面網站常見透過hamburger選單收合的滿版menu)。

修正點擊便利貼文字造成的距離差
修正點擊便利貼文字造成的距離差

加入刪除便利貼功能

刪除的概念可以想成「從包著便利貼id的陣列中,運用語法 splice() 切掉該張便利貼的id」。在colorList中新增刪除按鈕如下:

button.btn(@click="postits.splice(pid,1)") 刪除

新增 / 刪除的transition

接著加入新增和刪除的動畫,我們使用vue的transition group處理。在使用上有以下幾點特性:

  1. 在HTML新增,transition-group(name="fade"),注意transition Group需要包成一個div使用,這邊用tag="ul"處理,而便利貼為li
  2. Group內的每個物件都需要名字,才知道控制動畫的元件範圍,給他:key="pid",每張便利貼都有個獨一無二的id

利用vue官方提供的效果fade稍微調整一下語法,加入scale讓便利貼有從小變大、長出來的效果。

//HTML
#app
  transition-group(name="fade", tag="ul")
    li.postit(v-for="(p,pid) in postits",
            //為每張便利貼加上一個id
            :key="pid",
            :style="postitCss(p)",
            @mousedown="selectId($event,pid)")
      .text {{p.text}}
//CSS
.fade-enter-active, .fade-leave-active 
  transition: .5s

.fade-enter, .fade-leave-to 
  opacity: 0
  transform: scale(0.1)
新增 / 刪除的transition
新增 / 刪除的transition

調整顏色控制列的位置

為了讓修改顏色的功能更人性化一些,我們把.colorList整包移到.postit裡面,用position: absolute定位在便利貼下方。這時你會發現熟悉的點擊距離差問題又回來了,但因爲修改顏色和刪除的機制也是透過滑鼠,所以無法使用之前的方法來解決。

先前拖曳功能的設定為——點擊便利貼時,將該張便利貼設定id為0,當滑鼠移動時同步更新設定。現在把控制列跟便利貼拆成不同部分,也就是說點擊控制列時不進行id的設定。

selectId的event中判斷source element是否含有blockbtn,如果沒有,則進行id的設定,如果有,則nowId=-1

//CSS
.colorList
  position: absolute
  bottom: -80px
  display: flex
  flex-direction: row
  .block
    margin-right: 10px
//JavaScript
selectId(evt,id){
  console.log(evt)
  let isBlock = evt.srcElement.classList.contains('block')
  let isBtn = evt.srcElement.classList.contains('btn')
  if (!isBlock && !isBtn ){
    this.nowId=id //滑鼠點下去
    this.startMousePos = {
      x: evt.offsetX,
      y: evt.offsetY
    }
  }else{
    this.nowId=-1
  }
}
調整顏色控制列的位置
調整顏色控制列的位置

文字編輯和多行文字時呈現的大小

如同調整顏色的控制列,我們希望在編輯文字部分可以有更好的使用者體驗,透過點擊該張便利的「編輯」按鈕即可修改。在Vue裡增加 setText 這個方法,利用語法 prompt() 跳出修改視窗,並在input欄位顯示原始的文字(透過抓取pid知道是哪張便利貼、上面有甚麼文字):

//HTML
//新增編輯按鈕
button.btn(@click="setText(pid)") 編輯
//JavaScript
methods:{
  ...
  setText(pid){
    //彈出視窗修改文字
    let text = prompt("請輸入新的文字", this.postits[pid].text)
    //送出之後再便利貼上更新文字
    if (text){
      this.postits[pid].text=text
    }
  }
}
文字編輯和多行文字時呈現的大小
文字編輯和多行文字時呈現的大小

連接Firebase資料庫

接下來進入今天的重頭戲——串接Firebase資料庫。Firebase是Google提供的雲端開發平台,協助 開發者在雲端快速建置後端服務,提供即時資料庫。這種noSQL(非關聯式)類型的資料後端平台可能是未來的趨勢,noSQL代表你不會用像select all member這種特殊的資料查詢語法,他就是一張樹狀圖,把所有東西塞進去,所以你可以看到便利貼在頁面上即時地移動與資料修改,在Firebase資料庫裡也可以看到頁面上的改動。

首先前往Firebase的控制台,新增一個for便利貼的專案。

接著選擇Realtime Database,在專案中新增child如下:

tips: 右邊的值必須要先輸入一個default數值,之後有資料存入時便會被取代掉了。

接著引入我們的codepen網頁,在codepen引進CDN,再初始化資料庫。

Step 1:進到Overview,點選「網頁」。

Step 1:進到Overview,點選「網頁」。
Step 1:進到Overview,點選「網頁」。

Step 2:將Firebase新增至codepen。CDN為第一個script內的src,初始化config為下方的firebaseConfig。

Step 2:將Firebase新增至codepen,初始化config為下方的firebaseConfig。

Step 3:引入CDN,第一個script內的src貼入codepen settings。

Step 3:引入CDN,第一個script內的src貼入codepen settings。
Step 3:引入CDN,第一個script內的src貼入codepen settings。

Step 4:初始化資料庫,將Step 2裡面第二個script中的程式碼複製貼在我們JS程式碼的最上方。

Step 4:初始化資料庫,將Step 2裡面第二個script中的程式碼複製貼在我們JS程式碼的最上方。
Step 4:初始化資料庫,將Step 2裡面第二個script中的程式碼複製貼在我們JS程式碼的最上方。

接著透過Firebase手動新增一張便利貼如下,注意資料的層級,尤其是代表便利貼位置的x, y是在pos下面。

透過Firebase手動新增一張便利貼
透過Firebase手動新增一張便利貼

再把codepen跟建立好的firebase資料庫串接,並監聽他的value做即時更新,可以看到我們剛剛手動在資料庫新增的便利貼。Firebase語法可參考官方文件

//JavaScript
var postitsRef = firebase.database().ref("postits2"); //建立連結
  postitsRef.on('value', (snapshot)=>{
   vm.postits = snapshot.val() //即時更新
  })

註:firebase串接語法已更新成firebase.database().ref(),直播內容的firebase.database.ref()為舊版。

把codepen跟建立好的firebase資料庫串接,並監聽他的value做即時更新
把codepen跟建立好的firebase資料庫串接,並監聽他的value做即時更新

遠端新增 / 刪除便利貼

可以透過資料庫新增並呈現在頁面上後,我們這邊試試透過codepen push便利貼進去資料庫,修改methods addPostits的地方,讓他不是新增在vm這邊而是postitsRef

//JavaScript
addPostits(){
  postitsRef.push(
    {
      text: "文字",
      color: "yellow",
      pos: {x: 200+Math.random()*100, y: 200+Math.random()*100 }
    }

我們希望能刪除特定便利貼的節點,也就是postitsRef下的子結點,記得也需修改HTML刪除按鈕的語法為@click="deletePostit(pid)",並在JS新增以下methods:

deletePostit(pid){
  postitsRef.child(pid).remove();
}

同步顏色 / 文字 / 拖移位置

除了更新頁面上便利貼的位置,也同步更新遠端資料庫的位置,所以在mousePos抓這張便利貼this.nowId,設定set更新遠端資料庫的值。

//JavaScript
postitsRef.child(this.nowId).set(this.postits[this.nowId])

同步文字的邏輯也是類似的,在setText做完本地更新後,也一起更改資料庫的文字。

//JavaScript
postitsRef.child(pid).set(this.postits[pid])

最後一個則是顏色,我們原先是讓便利貼的顏色等於顏色的名字p.color=color.name,現在為了更新遠端資料 ,我們把它包成一個function叫setColor。在methods定義setColor的作用,概念和setText類似。

//HTML
.colorList
  .block(v-for="color in colorList",
     :style="{backgroundColor: color.color}",
         //修改成成為setColor function
     @click="setColor(pid, color.name)")
//JavaScript
setColor(pid,colorname){
  this.postits[pid].color=colorname
  postitsRef.child(pid).set(this.postits[pid])
},

以上就是這次的直播內容,主要聚焦於功能的優化與資料庫的串接,後面firebase的部分對於初次接觸的人可能會需要一段時間的摸索,但只要成功串接起來、再多研究一下文件,就會比較好入手。

步驟總結

這次的直播內容比較複雜,所以在最後來個總重點整理一下。在上篇我們先建立便利貼的基礎,從樣式雛形到基本資料處理,可以分為以下幾個重點:

1. 便利貼樣式與資料處理 – 建立便利貼架構,色票、文字樣式和文字位置
2. 加上滑鼠互動事件 – 紀錄滑鼠移動的位置並儲存在evt,運用nowId判斷滑鼠在哪一張便利貼的範圍裡面
3. 新增便利貼與修改顏色 – 做一個button點擊觸發function addPostits,在addPostits推入新的陣列

下篇的部分我們著重在既有功能的微調、更精緻化,還有資料庫的串接:

1. 修正點擊便利貼文字造成的距離差 – pointer-events: none停止觸發任何的點選事件
2. 刪除便利貼功能 – 運用語法splice()切掉該張便利貼的id
3. 新增 / 刪除的transition – 使用vue的原生transition group處理,transition-group(name=”fade”)
4. 調整顏色控制列的位置 – 把colorList整包移postit裡面,用position: absolute定位在便利貼下方
5. 文字編輯和多行文字時呈現的大小 – 利用語法prompt()跳出修改視窗,優化文字編輯的使用者體驗
6. 連接Firebase資料庫 – 在Firebase建立專案與Realtime Database,與Codepen資料連接
7. 同步顏色 / 文字 / 拖移位置 – 在mousePos抓特定便利貼this.nowId,設定set更新遠端資料庫的值

課程推薦

動畫互動網頁程式入門(HTML/CSS/JS)以簡單例子帶你入門網站的基礎架構及開發,用素材刻出簡單有趣又美觀的網頁和動畫,享受做出獨一無二的網頁所帶來的成就感,在職場上與設計師和工程師合作無間。

打好基本的互動網頁基礎之後,可以進階動畫互動網頁特效入門(JS/CANVAS),紮實掌握JavaScript 程式與動畫基礎以及進階互動,整合應用掌控資料與顯示的Vue.js前端框架,完成具有設計感的互動網站。

那我們下次再見啦👋👋👋

此篇直播筆記由幫手 Jeudi Kuo 協助整理

墨雨設計banner

這篇文章 用Vue.js做快速換色與整理的便利貼牆吧!(下)(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
用Vue.js做快速換色與整理的便利貼牆吧!(上)(直播筆記) https://creativecoding.in/2021/07/05/%e7%94%a8vue-js%e5%81%9a%e5%bf%ab%e9%80%9f%e6%8f%9b%e8%89%b2%e8%88%87%e6%95%b4%e7%90%86%e7%9a%84%e4%be%bf%e5%88%a9%e8%b2%bc%e7%89%86%e5%90%a7-%e4%b8%8a/ Mon, 05 Jul 2021 01:31:00 +0000 https://creativecoding.in/?p=1154 需要發想靈感、紀錄個人代辦清單,或和他人討論嗎?製作一個能夠自由編輯、增刪、變色、拖曳編排的便利貼牆網頁,多個願望一次滿足。上集我們使用Pug、Sass及Vue.js刻出便利貼的基本功能。

這篇文章 用Vue.js做快速換色與整理的便利貼牆吧!(上)(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
在需要發想靈感的職業日常中,便利貼常常作為靈感紀錄與討論道具,有著不可取代的重要性,但困擾的是常常黏性一過,原先貼得整整齊齊的便利貼只要一有風吹草動,就如同十二月的雪一樣翩翩飛舞。如果可以把這些小傢伙電子化,豈不是美事一樁?今天我們就要用Vue.js來實作可以快速地新增、輸入內容、換色、刪除甚至拖曳編排的便利貼牆。這一次的案例因為比較複雜,所以切成兩篇來做,請上下兩篇搭配一起服用唷~

用Vue.js做換色與快速整理的便利貼牆吧!(上)成品圖
用Vue.js做換色與快速整理的便利貼牆吧!(上)成品圖

我們將以Code Pen做為本次實作的平台,這是一個可以在創作的同時即時看到程式碼運作狀況的線上程式碼編輯器,只要簡單註冊就可以使用囉!

如果想搭配直播影片一起實作,請👉🏻往這邊走

了解架構

在開始之前我們先來概念性的發想,便利貼的結構設計可分為以下這些方向:

  1. 儲存的資料種類—文字(顏色名稱)和色票
  2. 文字呈現方式—文字在便利貼上應該滿版呈現,隨著文字多寡而動態調整大小
  3. 拖曳功能—滑鼠點擊在便利貼上時紀錄初始座標,到結束時動態計算中間的滑動呈現
  4. 小功能—切換文字、刪除等功能

首先在Code Pen上開一個新的pen,將HTML的預處理器設定成Pug、CSS的預處理器設定成Sass、JS的CDN掛入Vue。

準備好Code Pen中的環境
準備好Code Pen中的環境

便利貼樣式與資料處理

接著我們開始從第一張便利貼刻起,便利貼的結構簡單來說就是一個裝有文字的框框,文字資料我們先暫時寫死,稍後再用Vue.js動態更新。

在HTML給他一個容器名為postit裡面裝一些文字text,接著在CSS設定他的樣式如下,如次便能得到一個文字在中間的基礎白色便利貼:

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap')
*, *:before, *:after
  border: solid 1px //之後再把邊線取消掉
  font-family: 'Noto Sans', sans-serif
@mixin size($w, $h:$w)
  width: $w
  height: $h

$colorBlack:#3E3A39

html, body
  // background-color: $colorBlack //背景色,設定樣式時先拿掉方便識別
  
.postit
  +size(240px)
  font-size: calc( 240px / 4 - 5px ) //便利貼寬÷字數-預留空隙
  display: flex
  justify-content: center
  align-items: center
第一章便利貼

接下來替便利貼上一些活潑的顏色,讓他變得好玩一些,同時調整字的顏色跟上一些陰影來增加設計的細緻度,我們的第一張便利貼就完成了。使用的色票和陰影處理如下,大家也可以自由選擇喜歡的顏色唷:

//修改字體顏色不要太死黑
color: #44403F

//便利貼顏色
$colorYellow: #FFEB67
$colorBlue: #A5D8D6
$colorRed: #EF898C
$colorGreen: #CBE196

.postit
	background-color: $colorYellow
  letter-spacing: 5px
  font-weight: 500
  box-shadow: 15px 10px 40px rgba(black,0.4)
調整便利貼的顏色、陰影
調整便利貼的顏色、陰影

接下來進行資料的處理,在JavaScript裡給予一組陣列名為postits,裡面裝便利貼會用到的參數textcolorposition。接著新增一個new Vue並指定作用範圍為#app,抓出物件便利貼跟他是第幾張(p,pid) in postits,將文字套進{{p.text}}。用左下角的Console檢查資料是否連接好,先輸入vm之後,再輸入vm.$data.postits[0].text="temp"資料,如果出現”temp”替換掉原先的文字「都市更新」就代表成功。

//Vue.js
var vm = new Vue({
  el: '#app',
  data: {
    postits: [
      {
        text: "都市更新",
        color: "yellow",
        pos: {x:20, y:0}
      }
    ]
  }
})
可替換內文的便利貼
可替換內文的便利貼

加上滑鼠互動事件

為了增加自由度,我們來替便利貼加上拖曳的功能。拖曳代表著我們必須在螢幕上做絕對定位,當在拖動物件時,左上角的距離不斷地重複更新,要做到這項事情,首先我們必須將資料與定位綁定起來。

在CSS的.postit裡加上position: absolute,有時在Vue我們會動態地加上style,但這容易造成HTML程式碼裡拖了一長串反而不好閱讀,所以像這種共用性高的style可以考慮直接在CSS做設定。

接著在JS設定style的[methods](<https://cythilya.github.io/2017/04/17/vue-methods-and-event-handling/>)如下,然後帶入HTML的postit後,可在Console透過剛剛上面的方法改變文字來測試字型大小的調整是否成功。

methods:{
  postitCss(p){
    return {
      left: p.pos.x+"px", //動態地更新便利貼的位置
      top: p.pos.y+"px",
      'font-size': ((240-30) / p.text.length) +'px' //根據文字長度動態設定大小
    }
  }
}
修改CSS與JS綁定文字資料及位置,以便加上拖曳功能
修改CSS與JS綁定文字資料及位置,以便加上拖曳功能

顏色的設定跟文字的方法差不多,在JS的data裡面新增一個名為colorList的陣列,裡面塞入我們剛剛的色票與相對應的名字:

colorList: [
  {
    name:"yellow",
    color: "#FFEB67"
  },{
    name:"blue",
    color: "#A5D8D6"
  },{
    name:"red",
    color: "#EF898C"
  },{
    name:"green",
    color: "#CBE196"
  },{
    name:"black",
    color: "#3E3A39"
  }
],

接著在下方的methods裡return他的值。在Vue裡面你要抓他的值可以直接用this指向,定義條件用find過濾符合的資料。

//JavaScript
'background-color': this.colorList.find(o=>o.name==p.color).color

這時我們可以製作一個control pannel來快速調整便利貼內的文字跟顏色,省去一直打開Console輸入指令測試的重複步驟。在HTML新增一個ul放入li和輸入欄位inputinput分別對應到p.text抓取輸入文字內容和p.color選擇便利貼顏色,再設定他的css。

//HTML
ul.datalist
  li(v-for="(p,pid) in postits")
    input(v-model="p.text")
    input(v-model="p.color")
//css
.datalist
  position: fixed
  right: 20px
  top: 20px
  width: 30%
設定便利貼顏色
設定便利貼顏色

前面做了資料和定位的綁定後滑鼠靜止的部分搞定,接下來要做滑鼠移動時的行為,這部分比較複雜可能需要多一點時間理解唷。我們在整個畫面上紀錄滑鼠移動的位置並儲存在evt內,右鍵檢查裡面有一個參數offset代表滑鼠距離左上角的相對位置。

小筆記:evt代表event,每次滑鼠移動時會觸發的一連串事件,包括滑鼠位置、點擊放開等,都會儲存在這裏面。

//JavaScript
window.onmousemove = (evt)=>{
  //滑鼠移動時,將最新位置記錄到vue中
  // console.log(evt)
  vm.postits[0].pos.x=evt.pageX //設定第一張便利貼的x距等於滑鼠在頁面上的x距
  vm.postits[0].pos.y=evt.pageY //設定第一張便利貼的y距等於滑鼠在頁面上的y距
}
滑鼠移動更新其在Vue.js內的位置

現在便利貼會跟著滑鼠移動,但我們希望移動是滑鼠點擊觸發之後才發生的。所以需要在data的地方多儲存一個nowId: -1nowId代表滑鼠點擊但還沒放開時,滑鼠在哪一張便利貼的範圍裡面。

我們在HTML裡加上@mousedown="selectId(pid)"並綁定點擊事件放在methods裡面,新增滑鼠移開的事件。為了方便識別可以把nowId印在畫面上。

//JavaScript
var vm = new Vue({
  ...	
  data: {
    ...
    nowId: -1
  },
  methods: {
    ...
    selectId(id){
      console.log(id)
      this.nowId=id //滑鼠點擊時選擇該張便利貼
    }
  }
})

//滑鼠移動時,將最新位置記錄到vue中
window.onmousemove = (evt)=>{
  // console.log(evt)
  if (vm.nowId!= -1){
    vm.postits[vm.nowId].pos.x=evt.pageX //抓取第nowId張便利貼的x距等於滑鼠在頁面上的x距
    vm.postits[vm.nowId].pos.y=evt.pageY //抓取第nowId張便利貼的y距等於滑鼠在頁面上的y距
  }
}

window.onmouseup = (evt)=>{
  vm.nowId = -1 //滑鼠未點擊時沒有選擇任何便利貼
}
//HTML
#app
  .postit(v-for="(p,pid) in postits",
          :style="postitCss(p)",
          @mousedown="selectId(pid)")
    .text {{p.text}}


ul.datalist
//把nowId印在畫面上
  li
    h1(style="color: white") {{nowId}}
  ...
設定滑鼠點擊與未點擊時的判別與動作
設定滑鼠點擊與未點擊時的判別與動作

單用window.onmousemove = (evt)監測時可能會有些狀況,我們希望當滑鼠有變動時,就在Vue裡偵測資料的變動並針對位置做更新,所以我們新增watch偵測是否有選擇便利貼,如果有就把這張便利貼抓出來。這張便利貼會等於所有便利貼的第nowId個,知道第幾張後就去設定他的位置。

var vm = new Vue({
  data: {
    ...
    mousePos: {
      x:0, y:0
    }
  },	
  watch: {
    mousePos(){
      if (this.nowId!= -1){
        let nowPostit = this.postits[this.nowId]
        nowPostit.pos.x = this.mousePos.x
        nowPostit.pos.y = this.mousePos.y
      }
      console.log(this.mousePos)
    },
  ...
})

window.onmousemove = (evt)=>{
  // console.log(evt)
  vm.mousePos = {x: evt.pageX, y: evt.pageY}
  //if (vm.nowId!= -1){
    //vm.postits[vm.nowId].pos.x=evt.pageX
    //vm.postits[vm.nowId].pos.y=evt.pageY
  //}
  
}

記得把作用範圍撐開跟window一樣大,不然會無法運作。

//css
html, body, #app
  background-color: $colorBlack
  padding: 0
  margin: 0
  overflow: hidden
  +size(100%)

拖曳的功能就完成了,但這時點擊便利貼的右下角時會有一些偏移、跳一下,我們可以記錄這個偏移量並加上點擊的位置,這樣一減一加之後我們就可以讓他乖乖待在位置上。在HTML的selectId新增$event,也記錄第一個點下去的位置startMousePos

@mousedown="selectId($event,pid)"
var vm =new Vue({
  ...
  data: {
    ...
    startMousePos: {
      x: 0,
      y: 0
    }
  }
  ...
  methods: {
    ...
    selectId(evt,id){
      console.log(id)
      this.nowId=id //滑鼠點下去
      this.startMousePos = {
        x: evt.offsetX,
        y: evt.offsetY
      }
    }
  }
})

watch減掉偏移量,有滑鼠移動而且我們判斷當下那張便利貼存在的時候。這樣拖曳功能就大功告成啦。

watch: {
  mousePos(){
    if (this.nowId!= -1){
      let nowPostit = this.postits[this.nowId]
      nowPostit.pos.x = this.mousePos.x-this.startMousePos.x
      nowPostit.pos.y = this.mousePos.y-this.startMousePos.y
    }
    console.log(this.mousePos)
  }

如果想要將滑鼠拖曳的效果變得更滑順,可以在CSS的.postit裡面加上cursor: pointer試試效果。

新增與修改顏色

接下來我們來做「新增」的功能,做一個button點擊觸發functionaddPostits。在addPostits推入新的陣列,位置給予亂數Math.random才不會覆蓋在原有的便利貼上。

新增便利貼功能
新增便利貼功能
//HTML
  ul.datalist
    ...
    button(@click="addPostits") +新增便利貼

最後做個改顏色的功能,透過點擊動態渲染的小方塊來改變便利貼的顏色,參考如下。

ul.datalist
  li
    ...
    .colorList
      .block(v-for="color in colorList",:style="{backgroundColor: color.color}", @click="p.color=color.name")
//css
.block
  +size(30px)
  background-color: #fff
  display: inline-block
//JavaScript
methods: {
  //直接從現有顏色清單裡選取一顏色
  getColor(name){
    return this.colorList.find( o=>o.name==name)  
  }
  ...
}
製作顏色小方框,方便直接更換便利貼顏色
製作顏色小方框,方便直接更換便利貼顏色

總結

以上就是前半段的便利貼教學,我們先建立便利貼的基礎,從樣式雛形到基本資料處理,可以分為以下幾個重點:

1. 便利貼樣式與資料處理 – 建立便利貼架構,色票、文字樣式和文字位置

2. 加上滑鼠互動事件 – 紀錄滑鼠移動的位置並儲存在evt,運用nowId判斷滑鼠在哪一張便利貼的範圍裡面

3. 新增便利貼與修改顏色 – 做一個button點擊觸發function addPostits,在addPostits推入新的陣列

下一次我們會接續進行刪除、背景調整、縮放動畫等的功能,我們下次見啦👋👋👋

老闆的互動網頁課程

動畫互動網頁程式入門(HTML/CSS/JS)以簡單例子帶你入門網站的基礎架構及開發,用素材刻出簡單有趣又美觀的網頁和動畫,享受做出獨一無二的網頁所帶來的成就感,在職場上與設計師和工程師合作無間。

打好基本的互動網頁基礎之後,可以進階動畫互動網頁特效入門(JS/CANVAS),紮實掌握JavaScript 程式與動畫基礎以及進階互動,整合應用掌控資料與顯示的Vue.js前端框架,完成具有設計感的互動網站。期待在課程裡見到你!

此篇直播筆記由幫手 Jeudi Kuo 協助整理

墨雨設計banner

這篇文章 用Vue.js做快速換色與整理的便利貼牆吧!(上)(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
【p5.js創作教學】Aqua Planet 水色星球 – 來製作發光碰撞的行星吧!(直播筆記) https://creativecoding.in/2021/06/21/p5-js%e5%89%b5%e4%bd%9c%e6%95%99%e5%ad%b8-aqua-planet-%e6%b0%b4%e8%89%b2%e6%98%9f%e7%90%83/ Mon, 21 Jun 2021 02:26:00 +0000 https://creativecoding.in/?p=1109 利用p5.js程式一步步創作出會發光的水色星球粒子,並且增加弧形軌跡、連線、外圍刻度尺規等細節,讓整件作品完整且耐人尋味。

這篇文章 【p5.js創作教學】Aqua Planet 水色星球 – 來製作發光碰撞的行星吧!(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
夜晚抬頭望向天空,黑夜中有著數不盡的星星,讓人不禁讚嘆太空之美。今天老闆就要化身為太空人,觀察一顆由冷暖色調所搭配而成的星球。

一開始會先使用函式的方式來建構藍色粒子雲,隨後加上 noise 來形成動態效果,並加上橘色系的粒子來做搭配。建構好粒子後,便在粒子四周增加弧形的線條,圍繞著粒子雲,最後則是繪製尺標,讓整體作品看起來更有正在觀測的感覺。

《Aqua Planet 水色星球》完成品
《Aqua Planet 水色星球》完成品

透過此次互動藝術創作教學,你會學到

  • 學習函式的使用方式,如何透過參數的傳遞,來指定粒子雲的位置與半徑大小範圍
  • 如何應用極座標的概念,來繪製粒子的運動位置,並且使用 noise 的技巧讓粒子隨機移動
  • 透過不同色彩疊加的模式,來達成每項物件所期待產生的視覺效果

在開始製作之前你該知道的p5.js小技巧

就讓老闆帶你們一步步完成吧

《Aqua Planet 水色星球》步驟拆解圖
《Aqua Planet 水色星球》步驟拆解圖

1. 建立粒子系統

首先,先從建立最核心的粒子開始,老闆建立了planet(),並指定了三個參數,由前到後分別是 X 位置、Y 位置以及距離中心點位置的距離 r,可以注意到這邊的 r 在函式中給定了預設的30,這代表當我們呼叫函式的時候,如果第三個數字是沒有給定的,那 r 就會預設成 30,而目前呼叫的函式是有給定值 40 的。

在放置粒子的座標上,老闆將座標移動至畫布的中間,以中間向四周繪製大小、顏色不一的藍色粒子。顏色的部分,老闆到 https://coolors.co/ 網站選取想要的顏色,並複製網址後段色碼的區域,再將文字處理成可使用的色碼形式。

ellipse 的參數前兩項是位置,第三個是半徑,所以 ellipse(random(r), random(r), rr) 所代表的是「以畫布的中心點起,隨機在距離0到40之間的位置上,繪製半徑介於0到20之間的圓」。

//給定顏色
var colorsBlue = "04080f-507dbc-a1c6ea-bbd1ea-dae3e5".split("-").map(a=>"#"+a)

// 建立 planet 函式來繪製粒子
function planet(x,y, r=30){
  push()
    translate(x,y)
    for(var i=0;i<30;i++){
      // 隨機給定顏色
      let cc= random(colorsBlue) 
      fill(cc)
			
      // 繪製陰影
      drawingContext.shadowColor = color(cc)
      drawingContext.shadowBlur =30
  
      // 設定半徑範圍,並繪製粒子
      let rr = random(0,20)
      ellipse(random(r), random(r), rr)
    }
  pop()
}

function setup() {
  createCanvas(800, 800)
  background(0)
	
  // 混和模式設定成 SCREEN
  blendMode(SCREEN)
  planet(width/2, height/2, 40)
}

function draw() {
  // ellipse(mouseX, mouseY, 20, 20);
}
1. 建立粒子系統
1. 建立粒子系統

2. 用 noise 建立連續變化

首先,先將繪製粒子的 planet() 移動至 draw() 裡面,讓粒子可以隨時間不斷變化繪製位子。

老闆覺得目前粒子在分布上似乎不太均勻,所以打算改用極座標來做,使用極座標來設定位置的方式在其他作品裡也曾使用過,可以參考 【p5.js創作教學】來畫一個瘋狂的龍捲風吧!(直播筆記) 這篇文章。

為了讓上一個與下一個粒子的分布上不要呈現完全隨機跳動,所以這裡老闆使用了 noise 來設定粒子的距離 xx、角度 ang 以及半徑大小rr

而在設定上,第一眼看上去會覺得「這一串程式碼好長喔」,但其實拆解下來,可以看到老闆只用了幾個參數就產生隨機,分別是代表粒子序號的 i、系統變量(也就是計算程式啟動以來的幀數 frameCount),以及當滑鼠水平移動時也會產生影響的mouseX

而其他的常數則是老闆慢慢嘗試去調整出來的,可以理解成是每一個常數所影響占比,所除的數字越大,該變數所影響的量越小。你們也可以自己改變數字,試出最喜歡的樣子。

這裡要特別注意的是,老闆希望整個粒子雲可以呈現中間密外圍疏,所以在 xx 這個設定距離的參數上的尾端又多乘上一個 noise。此外,在星球顏色的變化上也改為使用 noise,會顯得更加地平順,不會一閃一閃的。

var colorsBlue = "04080f-507dbc-a1c6ea-bbd1ea-dae3e5".split("-").map(a=>"#"+a)

function planet(x,y,r=30){
  push()
    translate(x,y)
    for(var i=0;i<200;i++){
      // 顏色改為連續變化,這樣才不會閃閃的
      let cc = color(colorsBlue[int(noise(frameCount/10,i)*colorsBlue.length)%colorsBlue.length])
      fill(cc)
			
      drawingContext.shadowColor = color(cc)
      drawingContext.shadowBlur =30
			
      // 以極座標方式畫圓形位置
      // xx 乘上 noise,就會產生中間有比較多粒子的效果
      let xx = noise(i*2,frameCount/100+mouseX/500)*r*noise(i)*2 
      let ang = noise(i,frameCount/800+mouseX/1000,500)*10*PI
      let rr = noise(i,500,frameCount/50+mouseX/500)*40 
      ellipse(xx*cos(ang),xx*sin(ang),rr)
    }
  pop()
}

function setup() {
  createCanvas(800, 800)
  background(100)
  // planet(width/2, height/2, 100)
}

function draw() {
  blendMode(BLEND)
  // 加上外框
  fill('#0f1954')
  rect(0,0,width,height)
    
  blendMode(SCREEN)
  planet(width/2, height/2, 400) 
}
2. 用 noise 建立連續變化
2. 用 noise 建立連續變化

3. 加上暖色粒子與調整粒子大小

目前的畫面有些單調,所以想加上一些偏橘色粒子。由於都是粒子,增加的程式碼就直接寫在 planet 函式中,而且我們可以複製原本藍色粒子的片段去做修改,讓整體視覺變成冷暖色交替。但是如果只有更改顏色、粒子大小太相近的話,看上去有點喧賓奪主,所以稍微調整成藍色大橘色小,將橘色粒子的半徑大小改為 rr/2

除了不同顏色大小的調整外,在粒子半徑大小 rr 的設定上,老闆為了使離中心越遠的粒子顯得越小,加上了開平方 sqrt

/* 加上暖色色票 */
var colorsRed = "fe7f2d-fcca46-a1c181-619b8a-333".split("-").map(a=>"#"+a)

function planet(x,y,r=30){
  push()
    translate(x,y)
    for(var i=0;i<200;i++){
      let cc = color(colorsBlue[int(noise(frameCount/10,i)*colorsBlue.length)%colorsBlue.length])
      fill(cc)
			
      drawingContext.shadowColor = color(cc)
      drawingContext.shadowBlur =20
			

      let xx = noise(i*2,frameCount/100+mouseX/500)*r*noise(i)*2 
      let ang = noise(i,frameCount/800+mouseX/1000,500)*10*PI
      /* 加上 sqrt,讓靠近中心的粒子較大,越遠的粒子較小 */
      let rr = noise(i,500,frameCount/50+mouseY/500)*30*(15/(sqrt(xx)+1))
      ellipse(xx*cos(ang),xx*sin(ang),rr)
			
      /* 加上橘球 */
      let cc2 = colorsRed[int(noise(frameCount/10,i)*colorsBlue.length)%colorsBlue.length]
      fill(cc2)
			
      drawingContext.shadowColor = color(cc2)
      drawingContext.shadowBlur =10
      ellipse(xx*cos(ang*2),xx*sin(ang*2),rr/2)	
    }
  pop()
}
3. 加上暖色粒子與調整粒子大小

4. 加上線條與修正藍色粒子

這裡要來繪製類似魔法陣的線條,連接方式是將每一個粒子的位置相連接起來。

為了可以記錄上一個粒子現在粒子的位置來做連接,必須要新增變數lastXlastRlastAng 來記錄上一個粒子的位置,在函式中記得也要更新此次粒子的位置,來作為下一個粒子的參考位置。

然而,將所有點與之間都連接起來,線條太多了,所以老闆增加了 random()<0.1 的條件,使線條出現的頻率不會那麼高。

除了魔法陣外,老闆也繪製了弧形的線條,原本想要使用 line 一段一段繪製,但是發現這樣實在有些麻煩,所以就改以使用 arc 的方式來畫。與線條一樣,透過加上random() 的方式,讓畫面呈現一閃一閃的效果 。

在藍色粒子上,由於陰影有一點太不亮了,所以把陰影跟粒子分開來調整,另外增加了shadowCC 來設定陰影。

function planet(x,y,r=30){
  push()
    translate(x,y)
    /* 1. 設定變數做紀錄,以便於繪製點與點的連線 */
    let lastX, lastR, lastAng
		
    for(var i=0;i<200;i++){
      /* 2. 將藍色球跟其陰影分開設定透明度 */
      let cc = color(colorsBlue[int(noise(frameCount/10,i)*colorsBlue.length)%colorsBlue.length])
      cc.setAlpha(150)
      fill(cc)
			
      let shadowCC = color(cc) 
      shadowCC.setAlpha(255) 
      drawingContext.shadowColor = shadowCC; 
      drawingContext.shadowBlur =20;
				
      let xx = noise(i*2,frameCount/100+mouseX/500)*r*noise(i)*2 
      let ang = noise(i,frameCount/800+mouseX/1000,500)*10*PI
      let rr = noise(i,500,frameCount/50+mouseY/500)*30*(15/(sqrt(xx)+1))
      ellipse(xx*cos(ang),xx*sin(ang),rr)
	
      let cc2 = colorsRed[int(noise(frameCount/10,i)*colorsBlue.length)%colorsBlue.length]
      fill(cc2)
	
      drawingContext.shadowColor = color(cc2);
      drawingContext.shadowBlur =10;
      ellipse(xx*cos(ang*2),xx*sin(ang*2),rr/2)
				
      /* 3. 新增點與點連線 */
      if (lastX && random()<0.1){
        push()
          stroke(255,50)
	  line(xx*cos(ang),xx*sin(ang),lastX*cos(lastAng),lastX*sin(lastAng))
	pop()
      }
				
      /* 4. 新增外圍弧形線條 */
      if (random()<0.5){
        push()
          stroke(255,50)
          noFill()
          arc(0,0,xx,xx,ang,ang+PI)
        pop()
      }
				
      /* 5. 更新變數 */
      lastX=xx
      lastR=rr
      lastAng=ang
    }
  pop()
}
4. 加上線條與修正藍色粒子

5. 調整平衡,加上材質

做到一個階段,有雛型的樣子後,老闆習慣為畫面加上材質,新增材質共有三大步驟,分別是命名材質、設定材質、疊加材質。

  • 命名材質
    在全域中命名材質變數 let overAllTexture
  • 設定材質
    setup() 中設定材質的樣式
overAllTexture=createGraphics(width,height)
overAllTexture.loadPixels()
// noStroke()
for(var i=0;i<width+50;i++){
  for(var o=0;o<height+50;o++){
    overAllTexture.set(i,o,color(100,noise(i/3,o/3,i*o/50)*random([0,10,20])))
  }
}
overAllTexture.updatePixels()
  • 疊加材質
    在 draw() 中改變與色塊的混合模式
push()
  blendMode(MULTIPLY)
  image(overAllTexture,0,0)
pop()

新增好材質後,接下來要來調整一些粒子跟線條的細節,目前所繪製的球體有 200個,這裡我們改為 120個,看起來比較不擁擠,另外粒子雲發散的距離從400改為300,縮小其範圍。這時候會發現,旁邊的弧形線條都擠在最裡面的位置了,所以在 arc 的參數上都乘上 2 ,讓弧形向外擴長,同時也加上橘色色系在線條上,讓整個作品看起來更加一致。還有一點細節是老闆在此加上了 noise,這使線條多了動態感。

調整到這裡,老闆覺得中間的粒子與線條差不多了,所以開始嘗試往背景的著手。這裡老闆使用 Pow 畫成由內而外,根據距離中心點的不同,疊加了好幾層不同透明度的圓,形成了一圈一圈的圓形尺規,雖說是尺規,但不是規規矩矩一圈一圈等距的圓形,這邊可以先觀察下圖兩者的差異。

等差常數與Pow的比較

Pow 其實就是以前高中數學所學過的指數,必須有兩個參數 Pow(底數, 次方),而老闆所使用的次方數是小於 1 的,這樣所產生的效果是,數值越小時,轉換過後所產生的差異會越大。舉例子來說,pow(1000,0.9) – pow(900,0.9) = 46 < pow(200,0.9) – pow(100,0.9) = 46,所以仔細觀察可以看到,越內圈的間距是大於外圈之間的間距,而這樣小細節,讓所疊加的圓並非死板板的一格一格,而是更加產生更加靈活一點的漸層感。

/*1. 上下的半徑壓扁,並將顏色修改為跟橘球一樣 */
if (random()<0.5){
  push()
    stroke(cc2)
    noFill()
    arc(0,0,xx*2,xx*2,ang*2,ang*2+noise(i,frameCount/200))
  pop()
}


function draw() {
  blendMode(BLEND)
	
  fill(30, 35, 86, 50)
  rect(0,0,width,height)
  blendMode(SCREEN)
   /*2. 修正半徑範圍  */
  planet(width/2, height/2, 300) 
	
  push()
    blendMode(MULTIPLY)
    image(overAllTexture,0,0)
  pop()
	
  /*3. 加上圓形尺規  */
  stroke(255,50)
  noFill()
  blendMode(MULTIPLY)
  for(var i=0;i<width;i+=100){
    fill(150,map(i,width/2,width,0,20))
    ellipse(width/2,height/2,pow(i,0.9)*3,pow(i,0.9)*3)
  }
}
5. 調整平衡,加上材質

6. 加上漸層陰影與刻度

老闆希望那些橘色的小粒子可以多一些稜角,以搭配中心圓形的球,所以將橘色小粒子從 ellipse 改為 rect ,並且跟著軌跡去做旋轉,才不會那麼地死板。

//ellipse(xx*cos(ang*2),xx*sin(ang*2),rr/2)
/*將橘色粒子的球體改為方形 */
push()
  rectMode(CENTER)
  translate(xx*cos(ang*2),xx*sin(ang*2))
  rotate(ang*2)
  rotate(i)
  rect(0,0,sqrt(rr)*sin(frameCount/2+i)*2)
pop()

接下來就來畫一些橫軸及縱軸的尺規,來讓畫面上扭曲沒有固定的形體可以透過 2D 固定的線條搭配。這裡繪製出的是每隔五格會有一條相對長一點的線條,這樣看去上會更加有刻度感。

/* 加上尺規 */
blendMode(BLEND)
stroke(colorsRed[1])
  push()
    for(var i=0;i<width;i+=10){
      line(i,40,i,45+(i/10%5==0?15:0))
      line(40,i,45+(i/10%5==0?15:0),i)
      point(i,i)
    }
  pop()

最後老闆本來想要外面加上一整個外框來框住星球,有一種正在觀測星球的感覺,但感覺有些太死板,所以嘗試了一些半圓形或是扇形的形狀,最終決定在右下角加上五個弧狀的扇形作為點綴,並與前面繪製弧型一樣,使用了 arc 來畫,並且使用了 noise 來增加隨機動態感。

/*右下角加上點綴型外框 */
noFill()
strokeWeight(5)
drawingContext.shadowColor = colorsRed[1];
drawingContext.shadowBlur =30;
for(var i=0;i<5;i++){
  let aa =  noise(i,frameCount/10)*2
  arc(width/2,height/2,width-100-i*20,height-100-i*20,aa,aa + noise(i,frameCount/10)/2)
}
  drawingContext.shadowBlur =0;

  strokeWeight(2)
6. 加上漸層陰影與刻度即完成
6. 加上漸層陰影與刻度即完成

結語

我們總結一下這次的水色星球小品,製作過程可以分為三大部分:

  1. 粒子的繪製是此次作品的核心,學習到了如何使用函式來讓程式更加有彈性。當一開始繪製好藍色粒子後,可以直接複製部分原本的程式碼修改,不需要重新撰寫。另外在粒子的位置上,可以觀察到當老闆在使用極座標繪製粒子時,在不同地方都透過細節上的變化來增加豐富度,像是為了使粒子雲可以呈現中間密外圍疏,所以距離設定上增加了 noise,亦或是根據離中心不同距離而有不同的粒子大小所增加的 sqrt 等。
  2. 弧形與線條連接 – 透過新增變數來紀錄上一個點現在這個點之間的位置,藉此能夠將粒子之間以線來做連接,以及透過 arc 來繪製圍繞在粒子雲四周的弧形、軌跡,增添細節。
  3. 視覺上的調整,除了加入材質外,也新增了尺規與座標,這樣固定的物件,與中心的動態物件做為對比,視覺上在穩定與動態之間達到平衡。

這就是我們用p5.js寫出來的簡單的小作品啦!老闆的成品這邊去,也非常歡迎大家到社團裡跟我們分享你們完成的作品。

相同的繪製原理還能應用在甚麼作品上呢?若對p5.js寫成的互動藝術程式創作有興趣,歡迎加入老闆開的Hahow互動藝術程式創作入門課程,與另外將近兩千位同學一起創作吧!

此篇直播筆記由幫手 阮柏燁 協助整理

墨雨設計banner

這篇文章 【p5.js創作教學】Aqua Planet 水色星球 – 來製作發光碰撞的行星吧!(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
不是工程師也會寫的 Code!把程式當畫筆《互動藝術程式創作入門》學生作品 https://creativecoding.in/2021/06/09/%e4%b8%8d%e6%98%af%e5%b7%a5%e7%a8%8b%e5%b8%ab%e4%b9%9f%e6%9c%83%e5%af%ab-%e4%ba%92%e5%8b%95%e8%97%9d%e8%a1%93%e7%a8%8b%e5%bc%8f%e5%89%b5%e4%bd%9c%e5%85%a5%e9%96%80%e5%ad%b8%e7%94%9f%e4%bd%9c%e5%93%81/ Wed, 09 Jun 2021 02:48:00 +0000 https://creativecoding.in/?p=1019 無論你是工程師或藝術家,都可以透過p5.js創作生成式藝術。此篇文章精選《互動藝術程式創作入門》學生作品分享,更能了解程式藝術的不同可能性,一起加入Creative Coding創意寫碼的行列吧。

這篇文章 不是工程師也會寫的 Code!把程式當畫筆《互動藝術程式創作入門》學生作品 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
你有聽過 Creative Coding(創意寫碼)嗎?寫程式除了架網站與當駭客之外,還可以創作藝術!Creative Coding 是一種透過程式創作來表達的藝術形式,表現方式包含但不限於視覺、聲音、投影與裝置藝術等,橫跨所有相關互動開發的核心概念,便是 Creative Coding。

想要入門 Creative Coding,可以先從 p5.js 生成式藝術創作開始,p5.js – 一套專門給為藝術家的程式框架,無論你會不會寫程式、是不是工程師,都可以快速將你從生活周遭所得到的靈感,用程式表現出來。歡迎加入互動藝術程式創作入門(Creative Coding) 線上課程,與近 2,000 位線上同學們一起玩創意,表現自己!

在這之前,我們一起來看這堂課程的線上學生們,都拿起程式畫筆創作出什麼樣的作品吧!

日式小清新風的牛奶盒

來自 Coco Ke 的作品,因為想要呈現自己喜歡的日式小清新風格,所以使用帶有日常感的東西作排列組合,是非常用心的靈感搜集。

課程老師哲宇點評:在技術部分用到了比較進階的遮罩作法, 以及疊色的方式製造出雲狀的圖樣。其實沒有遮罩也很好看!有墨水暈出去的感覺,加上了材質感覺比單色的背景更有溫度。

《互動藝術程式創作入門》學生作品
Coco Ke的〈牛奶盒〉

窗花形狀疊加出畫面驚喜

來自 Ching-Wen Hsu 的作品,原本單純從窗花來的點子,但重複疊上去以後倒是有點像霧玻璃。

課程老師哲宇點評:在技術上雖然是使用較為單純的線條作畫,但是在位置變化上重疊很多次,加上些微的顏色變化,讓作品本身的動態感很足!建議利用類似的技巧加上組合不同的基礎圖形可以製造出大量不同的窗花,想必會有不一樣的畫面驚喜!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
Ching-Wen Hsu的〈窗花〉

Seawaves 滄海桑田

來自 Loxi 的作品,從滄海桑田這個概念發想,原先把海想成整塊,一直在「流動的水」上面掙扎,卻忽略程式本來就是透過無數細小的集合來模擬,想通以後才終於弄出能看的效果。

課程老師哲宇點評:像素等級的特效有種 Glitch 的數位雜訊感很酷,整體上也用到了比較進階的物件導向概念去管理一顆顆的水粒子。老師也特別強調,學習的過程中不用過度擔心臨摹借鏡,只要隨著創作的越來越多,會越熟悉這些技巧,就能上手組合成屬於自己的特別手法!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
Loxi的〈Seawaves〉

Elliptical Flourish 用程式展現生命力

來自 梁舜勛 的作品,希望能感受植物生長的過程。植物生長過程的本質很接近這樣生成藝術的方式,所以將兩者結合,用大地色系象徵土地和樹葉,用粉紅色作為強調色相並象徵花朵,展現植物的生命力和亂中有序的美。

課程老師哲宇點評:使用一系列的線條圓構成葉子,意外地很有植物的感覺!技巧部分使用亂數加上生成隨機顏色大小,與背景會逐漸讓軌跡變淡兩個組合起來,互動感蠻好玩的,淡掉之後很像某種桌巾圖案。在進階技巧部分,可以研究遞迴、L System、曲線等方向,可以生成更接近植物亂中有序感覺的作品喔!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
梁舜勛的〈Elliptical Flourish〉

詩中有花,花中有詩

來自 廖書賢 的作品。想到詩,就會想到一片美景,可以是山水,可以是黃昏,可以是人龍馬流。忽然有靈感,想要做花落繽紛的場景,突然想到 Daniel Shiffman 有做過雪花紛飛的場景,於是就拿這個為基底參考並修改成櫻花的樣式。

課程老師哲宇點評:櫻花的飄動感很漂亮,在畫面部分如果希望推得更多一些,可以嘗試使用不同字體,像是手寫、書法字,加上一個一個字進來的時候噴櫻花,或在字移動的時候,會產生風影響到周圍櫻花的移動之類的,也可以嘗試在畫面整理上蓋一層材質,會很有繪本的感覺!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
廖書賢的〈詩中有花,花中有詩〉

Ink Mountains 往山裡走去,用程式表現水墨溫度

來自 Loxi 的作品。單純想弄出一幅有水墨風格的畫。

課程老師哲宇點評:十分用心的作品,看起來也很有山水畫的感覺。剛開始學數位藝術的時候,要使用程式語言製作出有溫度、不死板的作品相對困難。這個作品很好好的應用了 noise(噪聲)多層次的疊合,讓山的形狀跟霧都看起來很自然,可以嘗試疊上材質、在山中再生成一些更小單位的坡或是樹,可以讓畫面感更強烈。

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
Loxi的〈Ink Mountains〉

Sierpinski pattern 用數學運算創造碎形效果

來自 Loxi 的作品。作品介紹是給我爆炸吧!!!碎形們(/。皿。)/︵╧╧.!!

課程老師哲宇點評:碎形的效果很有數位感,如果對數學產生圖形很有興趣,可以參考這個日本創作家Naoki Tsutae 的作品。Naoki Tsutae 擅長使用數學與餘數運算等特性製造各式各樣的碎形,而且程式都很短又精簡。更進階的話,可以往寫 shader 的方向發展,很適合寫這類型的碎形,也會更容易做出像素等級的特效互動!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
Loxi的〈Sierpinski pattern〉

有夠冷!與紅橘粒子一起取暖

來自 蔡旻勲 的作品。看久了很像紅、橘點點冷到一起取暖。

課程老師哲宇點評:紅橘點們感覺真的有點冷!白色粒子與藍色背景上留下的軌跡,呈現螢光的感覺,蠻漂亮的!也許可以嘗試用不同的幾何形狀跟著噪聲移動,例如很多小正方形跟著方形的軌跡移動、三角形跟著 60 度為單位的方向移動,再加上一些隨機的大小變化,就能變成一系列有趣的作品喔!

點此觀看動態原作品

《互動藝術程式創作入門》學生作品
蔡旻勲的〈有夠冷〉

看到這裡,你對 Creative Coding 更有興趣了嗎?

眼尖的你一定發現,現在有越來越多的互動藝術在我們周圍,如果你有去過一些台灣的藝文展覽或博物館,總會有幾件展品特別吸引你的注意力,用圖像或動畫來解釋抽象的概念,或創造想像與現實不同的世界,藉由探索去理解世界,也能讓想要傳達的故事更精彩。

也想大顯身手?

歡迎加入互動藝術程式創作入門(Creative Coding)線上課程,課程中你可以認識程式與互動藝術產業應用,開啟對工程跟設計的想像,學會使用 p5.js 開發互動介面,整合繪圖、音訊、視訊、文字、3D、互動與機器創作完整的作品,並將創作輸出應用在個人品牌或網站、主視覺或海報,甚至互動裝置、遊戲與教材製作等場景,讓你對進修的資源與路線更有方向。

期待你的加入!

撰文:Angela、吳哲宇

墨雨設計banner

這篇文章 不是工程師也會寫的 Code!把程式當畫筆《互動藝術程式創作入門》學生作品 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
【p5.js創作教學】來畫一個瘋狂的龍捲風吧!(直播筆記) https://creativecoding.in/2021/06/04/p5-js%e5%89%b5%e4%bd%9c%e6%95%99%e5%ad%b8-%e4%be%86%e7%95%ab%e4%b8%80%e5%80%8b%e7%98%8b%e7%8b%82%e7%9a%84%e9%be%8d%e6%8d%b2%e9%a2%a8%e5%90%a7/ Fri, 04 Jun 2021 02:23:00 +0000 https://creativecoding.in/?p=897 身為台灣人可能沒親眼看過龍捲風,但也大概它知道長甚麼樣子,威力又有多強大。今天我們要利用p5.js來完成瘋狂的龍捲風捲起乳牛與房屋的一張動態圖片。

這篇文章 【p5.js創作教學】來畫一個瘋狂的龍捲風吧!(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>
身為台灣人可能沒親眼看過龍捲風,但從新聞或影片畫面裡大概它知道長甚麼樣子,威力又有多強大。

瘋狂的龍捲風-成品

今天我們要利用p5.js來完成瘋狂的龍捲風捲起乳牛與房屋的一張動態圖片,在最一開始老闆當然是先嘗試著刻劃龍捲風的外型,接著分階段完成被龍捲風捲起的物體:乳牛以及穀倉,最後進行美術上的修改,包含了背景的顏色、加上材質以及調整龍捲風的線條等,最後加上滑鼠的互動來增加整體作品的豐富度。

透過此次互動藝術創作教學,你會學到

  • 以幾何圖形繪製龍捲風,其中涵蓋了線條的調整,使用透明的填色讓龍捲風有雲霧感
  • 如何應用極座標的概念,使用三角函數的觀念來繪製不規則飛行的物體的運動軌跡
  • 繪製漸層背景的技巧,以及透過旋轉來增加背景的動態感
想要更了解三角函數,歡迎閱讀這兩篇複習:
來用可怕的三角函數做網頁吧! – Part 1 衛星繞月球(直播筆記)
來用可怕的三角函數做網頁吧! -Part 2科幻時鐘(直播筆記)

在開始製作龍捲風之前,你該知道的p5.js小技巧

就讓老闆帶你們一步步完成吧!

利用p5.js創作《瘋狂的龍捲風》步驟拆解
利用p5.js創作《瘋狂的龍捲風》步驟拆解

1. 畫龍捲風

讓我們一起先來思考龍捲風看上去的樣子,它其實就是一層層圓圈,由下面的一個小圓圈開始慢慢地往上,圓圈變得越來越大。一開始我們先嘗試由上而下劃出一排圈圈,暫時不考慮大小的變化排列。

function setup() {
  createCanvas(800, 800);
  background(100);
}

function draw() {
  translate(width/2, 0)
    for(var i=0; i<height; i+=2){
      let nn = noise(i/10, frameCount/10)
      ellipse(0, i, nn*100)
    }
}
步驟一:畫龍捲風
步驟一:畫龍捲風

下一步要讓圈圈有大小區分的排列,我們必須由 “nn” 這個變數上來調整,在後面加上 “i” 這個變數,這樣一來,nn 的數字大小也會相對應地跟著從小到大。

function setup() {
  createCanvas(800, 800)
  background(100)
}

function draw() {
  translate(width/2, 0)
  for(var i=0; i<height; i+=2){
    let nn = noise(i/10, frameCount/10) + i/10
    ellipse(0, i, nn*10, nn*3)
  }
}
步驟一:畫龍捲風,慢慢修改形狀

然而這樣上面小、下面大的樣式並不是我們所要的,所以在 nn 變數中的 i 要改成 “height-i”,這樣才能讓數字由大到小排列,所畫出的樣子才會像是龍捲風的模樣。除了大小排列外,我們也順便將圖形刪除填色,留下僅有線條的樣子。
我們使用 nn 這個變數,可以發現它在一開始的時候有加上 noise 的效果,這是一個可以產生出隨機的變數,有了它,龍捲風看上去更增添動態感。

function setup() {
  createCanvas(800, 800)
  background(100)
}

function draw() {
  fill(0)
  rect(0,0,width,height)
  translate(width/2, 0)
  stroke(255)
  noFill()
  for(var i=0; i<height; i+=3){
    strokeWeight(random(2))
    let nn = noise(i/10, frameCount/100)*20+(height-i)/9
    ellipse(0, i-100, nn*8, nn*3)
  }
}
步驟一:畫龍捲風慢慢成形
步驟一:畫龍捲風慢慢成形

2. 加上被捲飛的物體

一開始我們必須思考物體被龍捲風捲起時的運動軌跡,先不用繪製乳牛、車子這些我們最後真正所要呈現的物體,先以簡單的方塊完成軌跡之後,最後再替換掉即可。

在物體位置的繪製上,我們要使用極座標的方式表示,極座標需給定半徑r,以及角度 θ,有了這兩個參數,那一個點在平面座標上就可以表示為 [rcosθ,rsinθ]。老闆使用 ang 表示角度, r 來表示半徑。設定好後,就使用 translate 來進行偏移。現在的原點位於整張圖中間最上方的位置,為了讓物體平均分散在整個龍捲風的周圍,所以在 y 座標中,會再加上 o*50,來讓物體是由上而下來進行分布的。

// 龍捲風
for(var i=0; i<height; i+=3){
    strokeWeight(random(2))
    let nn = noise(i/10, frameCount/100)*20+(height-i)/9
    ellipse(0, i-100, nn*8, nn*3)
}

// 飛行物體
for(var o=0;o<10;o++){
    let ang = o+frameCount/10
    let nn = noise(i/10,frameCount/100)*20+(height-i)/9
    let r = nn*10
    fill('blue')
    push()
        translate(cos(ang)*r,sin(ang)*r+o*50)
        rect(0,0,50,50)
    pop()
}
步驟二:加上被捲起的物件
步驟二:加上被捲起的物件

現在看上去,物體仍旋轉得很制式,這是因為每一個物體的角度是直接根據它是第幾個來去設定它的角度的。為了增加隨機性,我們增加一個 rot 變數,並且透過 noise 增加隨機性,設定好再使用rotate做旋轉。

// 飛行物體
for(var o=0;o<10;o++){
    let ang = o*5+frameCount/50
    let nn = noise(i/10,frameCount/100)*20+(height-i)/9
    let r = nn*(30+noise(o,frameCount/50)*5)
    let rot = noise(o,frameCount/100)*10
    fill('blue')
    push()
        translate(cos(ang)*r,sin(ang)*r+o*50)
        rotate(rot)
        fill('white')
        rect(0,0,50,50)
    pop()
}
步驟二:為被捲起的物件增加隨機性

3. 畫牛

設定好物體的旋轉方式後,我們來將方塊換成牛隻。在牛的繪製上可大致分成頭部、身體以及腳。為了使牛看起來精緻可愛,所以這裡大多都是由基本形狀如圓形、方形等等所構成,在這裡就是要考驗大家一筆一筆繪製、調整的耐心了。 這裡比較要注意的是,為了讓牛看起來比較生動些,我們將腳加上一些動畫,不管是前腳還是後腳,老闆都讓它左右邊的腳相差大約一個 PI 的角度左右,腳擺動起來才不會那麼地生硬。

另外,由於現在物體都是被龍捲風吹起來亂亂飛的,有點看不清楚到底有沒有把牛畫正,所以這裡會在 draw() 加入 drawCow(50, height-50),讓下方有一個固定的牛隻方便參考。

function drawCow(x,y){
  push()
    //身體
    translate(x,y)
    fill(255)
    noStroke()
    rect(0,0,50,25,5)
    fill(0)
    rect(5,0,12,15,5)
    rect(25,10,10,10,5)
    rect(45,5,5,10,5)

    // 後腳
    fill(255)
    push()
      translate(3,20)
      push()
        rotate(sin(frameCount/35))
        rect(0,0,5,20,5)
      pop()
      push()
        translate(5,0)
        rotate(sin(frameCount/20+PI))
        rect(0,0,5,20,5)
      pop()
    pop()

    // 前腳
    push()
      translate(40,20)
      push()
        rotate(sin(frameCount/35))
        rect(0,0,5,20,5)
      pop()
      push()
        translate(5,0)
        rotate(sin(frameCount/20+PI))
        rect(0,0,5,20,5)
      pop()
    pop()

    //頭部
    translate(-22,-5)
    rect(0,0,20,25,5)
    fill(255, 179, 160)
    rect(0,15,20,10,5)
    fill(0,60)

    ellipse(6,20,6)
    ellipse(14,20,6)
    fill(0)
    ellipse(5,8,3)
    ellipse(15,8,3)
    fill(247, 216, 150)
    rect(0,-8,3,10,10)
    rect(16,-8,3,10,10)

  pop()
}

// 飛行物體
for(var o=0;o<10;o++){
    let ang = o*5+frameCount/50
    let nn = noise(i/10,frameCount/100)*20+(height-i)/9
    let r = nn*(30+noise(o,frameCount/50)*5)
    let rot = noise(o,frameCount/100)*10
    fill('blue')
    push()
        translate(cos(ang)*r,sin(ang)*r+o*50)
        rotate(rot)
        drawCow(0,0)
        // fill('white')
        // rect(0,0,50,50)
    pop()
}
drawCow(50, height-50)
步驟三:畫牛
步驟三:畫牛

4. 調整龍捲風視覺 + 天空上色

第四部分一開始先將天空調整成偏向綠色外,其餘都是調整龍捲風的視覺,調整內容有以下幾點:

  • 加上陰影
    不管是龍捲風或是飛行的牛隻,都在繪製之前加上陰影,先是指定顏色,接著再去設定其偏移的量
drawingContext.shadowColor = color(0,30);
drawingContext.shadowOffsetY = 0
drawingContext.shadowOffsetX = 0
  • 以 arc 繪製龍捲風線條
    原本繪製的方式是使用 ellipse 形成一個完整的圓,我們改以 arc 角度來繪製,使用 sin 來設定龍捲風的起始位置後,再放入 arc 中,這樣子這樣子看起來更像是旋風。
  • 左右移動
    身為一個龍捲風,左右搖擺起來是一定要的,所以在 translate 的 x 位置再加上 cos(frameCount/10)*10,讓整個龍捲風搖擺起來。
  • 線條與填色
    將構成龍捲風線條註解起來,並且新增填色 fill,讓龍捲風以一個雲霧的感覺呈現

上述幾點調整的位置都是 draw() 中,修改後程式碼如下

function draw() {
  fill("#9BC1BC")
  noStroke()
  rect(0,0,width,height)
  translate(width/2 + cos(frameCount/10)*10,0)

  // stroke(255,100) // 拿掉 stroke
  noFill()

  // 龍捲風
  drawingContext.shadowColor = color(0,30);
  drawingContext.shadowOffsetY = 0
  drawingContext.shadowOffsetX = 0
  for(var i=0; i<height; i+=4){
    strokeWeight(random(1)+2)
    fill(255,30) // 加上填色
    let nn = noise(i/10, frameCount/100)*20+(height-i)/9
    let stAng = sin(i+frameCount/2)
    arc(0,i-100,nn*8,nn*3,stAng,stAng+PI*1.5)
  }


  // 飛行物體
  noStroke()
  drawingContext.shadowColor = color(0,30);
  drawingContext.shadowOffsetY = 2
  drawingContext.shadowOffsetX = 2
  for(var o=0;o<10;o++){
    let ang = o*5+frameCount/50
    let nn = noise(i/10,frameCount/100)*20+(height-i)/9
    let r = nn*(30+noise(o,frameCount/50)*5)
    let rot = noise(o,frameCount/100)*10
    fill('blue')
    push()
      translate(cos(ang)*r,sin(ang)*r+o*50)
      rotate(rot)
      drawCow(0,0)
    pop()
  }
  drawCow(50, height-50)
}
步驟四:調整龍捲風視覺以及將天空上色
步驟四:調整龍捲風視覺以及將天空上色

5. 漸層天空

我們要把原本單色系背景改為漸層天空,先將原本的背景註解起來。在繪製漸層背景上,首先先指定一個稍微偏綠色的藍,接著每隔一層線條就加上數值五的藍色,使其越來越偏向藍色,但是單純只有漸層似乎還是有點單調,畢竟此次的主題是龍捲風,所以老闆同時也加上不規則的旋轉,使整體更加有一種不受控制的感覺。

// 漸層背景
let cc = color("#6AD5CB")

push()
  rectMode(CENTER)
  for(var i=0;i<height;i+=100){
    push()
      cc.setBlue(cc._getBlue()+5)
      fill(cc)
      rotate(random(-1,1)/10)
      rect(width/2,i,width*1.2,100)
    pop()
  }
pop()


// 原本的背景
// fill("#9BC1BC")
// noStroke()
// rect(0,0,width,height)
步驟五:將天空改為漸層有生命力
步驟五:將天空改為漸層有生命力

6. 加上材質

為了增加一點繪畫感,我們可以為整個畫面新增材質疊加。共有三大步驟,分別是命名材質、設定材質、疊加材質。

  • 命名材質
    在全域的區域命名材質變數 let overAllTexture
  • 設定材質
    setup() 中設定材質的樣式
overAllTexture.loadPixels()
// noStroke()
for(var i=0;i<width+50;i++){
  for(var o=0;o<height+50;o++){
    overAllTexture.set(i,o,color(100,noise(i/3,o/3,i*o/50)*random([0,30,50])))
  }
}
overAllTexture.updatePixels()
  • 疊加材質

setup() 中改變與色塊的混合模式

push()
    blendMode(MULTIPLY)
    image(overAllTexture,0,0)
pop()
步驟六:為畫面增添繪畫感
步驟六:為畫面增添繪畫感

加上材質後,畫面上黑色一條一條的痕跡更明顯了,我們稍微將它修正成沒有線條,並且改變透明度。

push()
let cc = color("#6AD5CB")
cc.setAlpha(100) // 設定透明度
noStroke() // 設定沒有線條
  push()
    rectMode(CENTER)
    for(var i=0;i<height;i+=100){
      push()
        cc.setBlue(cc._getBlue()+5)
        fill(cc)
        rotate(random(-1,1)/10)
        rect(width/2,i,width*1.2,100)
      pop()
   }
  pop()

// fill("#9BC1BC")
// noStroke()
// rect(0,0,width,height)
步驟六:修正背景線條
步驟六:修正背景線條

7. 加入穀倉

在畫穀倉上也沒有太高深的技巧,與繪製牛一樣,像個手工業一樣慢慢一筆一畫描繪出來。不過有一個比較少看到的用法是 shearX ,它可以將物體沿著X軸歪斜指定角度,用來協助繪製梯形的屋頂。 另外老闆在生成這些穀倉時,並沒有再多寫一個迴圈,而是直接用餘數的方式去決定要生成牛還是穀倉。原先放在左下角當成繪製參考的穀倉也沒有拿掉,因為老闆後來覺得將單一穀倉就這樣固定在那裏也不錯。

function drawHouse(x,y){
  push()
    translate(x,y)
    // rect(0,0,100,50)
    fill(199, 77, 93)
    rect(20,0,80,40)
    fill(219, 77, 93)
    rect(0,0,80,40)
    fill(255,50)
    rect(0,0,80,6)

    stroke(255,100)
    strokeWeight(2)
    noFill()
    rect(40,10,20,10)
    rect(40,20,20,10)
    rect(40,10,10,20)
    noStroke()

    //屋頂
    shearX(PI/12)
    fill(68, 61, 63)
    rect(20,0,80,-20)
    shearX(-PI/6)
    fill(58, 51, 53)
    rect(0,0,80,-20)
  pop()
}
// drawCow(0,0)
if (o%6!=0){
  drawCow(0,0)
}else{
  drawHouse(0,0)
}
步驟七:繪製穀倉
步驟七:繪製穀倉

8. 修飾細節跟最後收尾

translate 加上與滑鼠 mouseX 做互動

// translate(width/2 + cos(frameCount/10)*10,0)
translate(width/2 + cos(frameCount/20 + mouseX/50)*50,0) // 加上 mouse

龍捲風的細線條隨機出現

for(var i=0; i<height; i+=4){
  strokeWeight(random(1)+2)
  fill(255,10) // 加上填色

  // 隨機出現線條
  if (random()<0.1){
    stroke(255)
  }else{
    noStroke()
  }

  let nn = noise(i/10, frameCount/100)*20+(height-i)/9
  let stAng = sin(i+frameCount/2)
  arc(0,i-100,nn*8,nn*3,stAng,stAng+PI*1.5)
}
步驟八:最後修飾及收尾即完成

結語

我們總結一下這次的龍捲風小品,製作過程可以分為三大部分:

  1. 龍捲風的繪製,思考龍捲風的模樣以及它具有什麼特性,我們可以用什麼圖形以及線條去模擬,從最一開始使用圓形來構成龍捲風的架構,慢慢地調整細節,讓它更加接近真實的模樣。
  2. 被捲起的物體 – 乳牛與穀倉兩者所使用技巧都是用基本的圖形建構而成。另外使用極座標表示被捲起的軌跡也是相當值得學習的技巧。
  3. 視覺上的調整,加入材質以及漸層背景等應用,以及滑鼠的簡單互動讓作品更加完整。

這就是我們用p5.js寫出來的簡單的小作品啦!相同的繪製原理還能應用在甚麼作品上呢?你們也可以參考老闆這件作品的OpenProcessing頁面,一起來切磋吧!

若對互動藝術程式創作有興趣,歡迎加入老闆開的Hahow課程互動藝術程式創作入門,與其他兩千位同學一起創作吧!

墨雨設計banner

訂閱 Creative Coding Taiwan 電子報:

這篇文章 【p5.js創作教學】來畫一個瘋狂的龍捲風吧!(直播筆記) 最早出現於 Creative Coding TW - 互動程式創作台灣站

]]>