Canvas基礎-粒子動畫Part2

緊接上一篇文章 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同樣,分別表示,圓心座標和半徑,新增的幾個含義以下:程序員

  • frameNum, 表示爲這個粒子當前在第幾幀;
  • frameCount, 表示一共有多少幀,通常來講咱們不會直接知道作完這個動畫一共有多少幀,因此這裏咱們是算出來的,parseInt(3000 / 16.66) 中3000表示3000毫秒,也就是整個動畫耗時3秒,而16.66是由於按60FPS來算,瀏覽器對每一幀畫面的渲染工做須要1秒 / 60 = 16.66毫秒,算出來以後再作個向上取整,就算出總幀數。
  • sx, 起始點x值,這裏爲了方便就寫死了,也能夠用隨機數;
  • sy, 起始點y值。

而後咱們來寫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

https://user-gold-cdn.xitu.io/2016/11/29/5128d9b5b92fc7aa189a99090704635d.gif

是否是感受被騙了,粒子總體移動,一開始一團團的,最後纔有點粒子化,粒子感不明顯,說好的酷炫狂拽屌炸天呢?瀏覽器

別急,知道個人尿性,不一開始把全部東西都說出來,而要把整個探索過程講清楚。這裏咱們不要將所有的粒子一次都放出去,咱們慢慢放。

首先在Dot對象裏面添加兩個屬性delaydelayCount

function Dot(centerX, centerY, radius) {
        .
        .
        .
        this.frameCount =  Math.ceil(3000 / 16.66);
        .
        .
        this.delay = this.frameCount*Math.random();
        this.delayCount = 0;
    }複製代碼
  • delay,這裏表示這個粒子要等待多少幀纔開始動,這裏簡單用總幀數和一個隨機數相乘。
  • delayCount,表示當前粒子以及等待了多少幀。

改完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) {
            .
            .
            .複製代碼

最後出來的效果:

https://user-gold-cdn.xitu.io/2016/11/29/780832f1dc60eeaa279e6a9e2751327e.gif

粒子化動畫的大體原理就是這樣的啦,隨着咱們給Dot對象添加更多的屬性,粒子動畫的想象空間仍是比較大的,好比加些顏色,加些運動軌跡,經過顏色和透明度作3D效果等等,下篇講講這個代碼的優化重構吧。

源碼地址: github.com/bob-chen/ca…

Part 1 地址: gold.xitu.io/post/57cda0…

Part 3 地址: gold.xitu.io/post/57e7a7…

碎碎念

最近總想記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,昨天終於動筆,在微信公衆號上寫,主要是扯淡和感悟,歡迎關注,交流。

微信公衆號:程序員的詩和遠方

公衆號ID : MonkeyCoder-Life

https://user-gold-cdn.xitu.io/2016/11/29/92d9e667c10e7d56e05b76c62ddb110d

參考

gsgd.co.uk/sandbox/jqu…

www.zybuluo.com/dengzhirong…

developers.google.com/web/fundame…

www.cnblogs.com/axes/p/3500…

相關文章
相關標籤/搜索