動畫其實就是一張張的影像,在非常短暫的時間內變化(例如每秒變換 16 張影像),近而產生視覺停留的效果。相信大家小時候都有畫過「翻頁動畫」,在一本小筆記本(或是國文課本哈哈哈)的每一頁都畫上一些小圖,快速翻動筆記本的頁面,小圖就會動起來。
每秒變化的 16 張的影像,這個影像就叫做「影格」Frame,若要實現動畫效果,那每張的影格都要有變化,不然看起來就會是靜止的唷!
在開發過程中,比較常會使用 css 的 animation ( keyframes ) 作出簡單且有規律的動畫,例如跳動、移動、轉動、淡入淡出等效果。例如下面的程式碼,非常好理解也好上手。只是若要實現更複雜的動畫例如遊戲常常出現的「物理原理」,包含重力、碰撞等等 keyframes 就難以滿足了。
const fadeInAnimation = keyframes`
0% {
transform: translate(0px, 100%)
}
100% {
transform: translate(0px, 0%)
}`;
const rotateAnimation = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
`;
當然現在也有些非常好用的動畫套件可以使用,例如 Lottie 就是我近期在專案有使用到的套件。Lottie 是由 Airbnb 開發出來,設計師可以運用 AE 軟體繪製出動畫後,轉檔成為 JSON 格式,讓工程師直接放入程式中,讓動畫完美呈現在網頁上。
有拿~麼~多好用的套件,為什麼還要用 Canvas 實踐動畫呢?除了比較虐之外,自己刻出來的動畫可能會很有成就感,也希望透過這個過程提升自己對時間和畫面的熟悉度。
要如何用 Canvas 實現動畫呢?你可以想像成用我們前幾天所學的方法繪製出圖片或是直接引用圖片,這些影像就是所謂的 iframe ,若要讓他有動起來的效果,我們需要在短短的時間內消除上一個影像,並繪製新的影像,重新繪圖好才能產生動畫效果。
如果繪圖的圖像本身非常複雜,那這樣的運算就會消耗許多運算資源和時間,所以一般在開發動畫或是遊戲是不會用 canvas 原生的方式刻出圖像的。但我們的練習都是非常小規模的所以可以不用擔心。
Canvas 動畫實踐需要重複以下四個步驟(內容參考至 mdn),大家可以想像一下,我們之前所學的繪圖都只是一個單一的 function ,我們在畫面初步渲染時就把影像畫好了。而動畫不一樣,我們需要一直重複執行繪圖的 function,好讓影像產生變化。我們又可以將這個過程分為四個步驟,分別是清除畫布、儲存畫布、繪製影像以及最後的復原畫布。
儲存畫布 save()
跟復原畫布 restore()
會在 canvas 中搭配使用,在之前的練習中我們一定都有遇過同一張畫布上的元素互相影響了彼此,使用 save()
跟 restore()
讓我們可以讓每一次的繪製不會影響到上一次的繪製。
save() 是保存畫布之前的狀態,相當於讓此圖像讓一塊新的畫布上操作,不用擔心影響到已經在 save()
之前就繪製好的圖像。而畫完影像後為了要讓畫布被還原成未操作過的樣子,就會再使用 restore()
,結束這次的繪圖。
// 繪製一個矩形
drawRect()
// 畫一個跟第一個矩形一樣但放大的矩形
ctx.save()
ctx.translate()
drawRect()
ctx.restore()
// 畫一個跟第一個矩形一樣但旋轉的矩形
ctx.save()
ctx.rotate()
drawRect()
ctx.restore()
上面就是繪製三個長方形但彼此不會受到影響的方法,也是我們在動畫中每一次繪製不同素材時都會使用到的方法。講到這裡~大家都對 Canvas 繪製動畫有了初步認識,明天我們再來看看如何讓這個 function 被呼叫,讓我們的動畫真的動起來吧!