緊接上一篇文章 Canvas基礎-粒子動畫Part1 其實這篇早在一個星期以前就應該發了,無奈事情太多,並且我又跑去寫微信公衆號了。javascript
有了上一篇的基礎,咱們已經能夠得到粒子,並將輪廓顯示在Canvas上,若是看了以前我寫的一些關於 Canvas動畫啊,畫圖啊什麼文章的話,其實應該已經很清楚如何去讓這些粒子動起來。html
這裏咱們從新定義一個draw2()
方法,init()
等仍是和Part1同樣,對圖片進行取樣,獲取粒子的位置,保存在Dot
對象裏面,這裏就省略了。java
要讓粒子動起來無非是不斷的計算粒子的位置,若是是線性增長的話,會比較生硬,這裏使用了Tween的緩動函數,能夠看一下jquery.easing.js裏面的緩動函數,直接拿來用就能夠了,效果不少,我這裏只選擇了一個easeInOut的效果。jquery
// t 當前時間
// b 初始值
// c 總位移
// d 總時間
function easeInOutCubic(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t + b;
return c/2*((t-=2)*t*t + 2) + b;
}複製代碼
有了緩動函數,咱們還須要在每一個Dot
對象中新增一些信息,git
function Dot(centerX, centerY, radius) {
this.x = centerX;
this.y = centerY;
this.radius = radius;
this.frameNum = 0;
this.frameCount = Math.ceil(3000 / 16.66);
this.sx = 400;
this.sy = 400;
}複製代碼
x,y,radius都和Part1同樣,分別表示,圓心座標和半徑,新增的幾個含義以下:程序員
parseInt(3000 / 16.66)
中3000表示3000毫秒,也就是整個動畫耗時3秒,而16.66是由於按60FPS來算,瀏覽器對每一幀畫面的渲染工做須要1秒 / 60 = 16.66毫秒
,算出來以後再作個向上取整,就算出總幀數。而後咱們來寫draw2
方法:github
var rafId = null,
finishCount = 0;
function draw2() {
var imgW = img.width,
imgH = img.height,
sx = winWidth/2-imgW/2,
sy = winHeight/2-imgH/2;
ctx.clearRect(0, 0, winWidth, winHeight);
ctx.fillStyle = "#000";
var len = dotList.length,
curDot = null,
frameNum = 0,
frameCount = 0,
curX, curY;
finishCount = 0;
for(var i=0; i < len; i+=1) {
// 當前粒子
curDot = dotList[i];
// 獲取當前的time和持續時間和延時
frameNum = curDot.frameNum;
frameCount = curDot.frameCount;
ctx.save();
ctx.beginPath();
if(frameNum < frameCount) {
curX = easeInOutCubic(frameNum, curDot.sx, curDot.x-curDot.sx, curDot.frameCount);
curY = easeInOutCubic(frameNum, curDot.sy, curDot.y-curDot.sy, curDot.frameCount);
ctx.arc(curX, curY, curDot.radius, 0, 2*Math.PI);
curDot.frameNum += 1;
} else {
ctx.arc(curDot.x, curDot.y, curDot.radius, 0, 2*Math.PI);
finishCount += 1;
}
ctx.fill();
ctx.restore();
if (finishCount >= len) {
cancelAnimationFrame(rafId);
return;
}
}
rafId = requestAnimationFrame(draw2);
}複製代碼
代碼雖然有點長,可是仍是比較好理解的。web
frameNum < frameCount
,經過前面的緩動函數計算出當前應該到達的x,y值,而後畫到Canvas上並將這個點的幀數加一。else
條件,就不要畫計算出來的值了,畫實際應該在的位置。ctx.beginPath()
和ctx.fill()
,否則你的畫布上啥子都沒有。finishCount
,用來在每次畫粒子的時候統計有多少個是已經跑到相應位置了,因此每次循環開始前都要將其置爲0,當跑到位的粒子數量和總粒子數量相等的時候,就調用cancelAnimationFrame
並退出,停掉相應的繪製,不要浪費資源。ctx.fill()
以後作,否則有會出現少了一個粒子的狀況。這樣出來的效果:canvas
是否是感受被騙了,粒子總體移動,一開始一團團的,最後纔有點粒子化,粒子感不明顯,說好的酷炫狂拽屌炸天呢?瀏覽器
別急,知道個人尿性,不一開始把全部東西都說出來,而要把整個探索過程講清楚。這裏咱們不要將所有的粒子一次都放出去,咱們慢慢放。
首先在Dot
對象裏面添加兩個屬性delay
和delayCount
。
function Dot(centerX, centerY, radius) {
.
.
.
this.frameCount = Math.ceil(3000 / 16.66);
.
.
this.delay = this.frameCount*Math.random();
this.delayCount = 0;
}複製代碼
改完Dot
對象以後,接下來的事情就好辦的,在循環開始以前現判斷一下是否達到等待幀數便可。
for(var i=0; i < len; i+=1) {
.
.
.
if(curDot.delayCount < curDot.delay){
curDot.delayCount += 1;
continue;
}
ctx.save();
ctx.beginPath();
if(frameNum < frameCount) {
.
.
.複製代碼
最後出來的效果:
粒子化動畫的大體原理就是這樣的啦,隨着咱們給Dot
對象添加更多的屬性,粒子動畫的想象空間仍是比較大的,好比加些顏色,加些運動軌跡,經過顏色和透明度作3D效果等等,下篇講講這個代碼的優化重構吧。
源碼地址: github.com/bob-chen/ca…
Part 1 地址: gold.xitu.io/post/57cda0…
Part 3 地址: gold.xitu.io/post/57e7a7…
最近總想記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,昨天終於動筆,在微信公衆號上寫,主要是扯淡和感悟,歡迎關注,交流。
微信公衆號:程序員的詩和遠方
公衆號ID : MonkeyCoder-Life