一步步打造Canvas小球動畫

咱們須要使用到Canvas的方法有:javascript

context.arc(x, y, r, sAngle, eAngle, counterclockwise);

第一步:繪製一個小球

var  canvas = document.getElementById('canvas'),
     ctx = canvas.getContext('2d'),
     w = canvas.width, //canvas畫布的寬
     h = canvas.height,// canvas畫布的高
     posX = 20,//定義圓心X座標
     posY = 20,//定義圓心Y座標 
     radius = 20;//定義半徑
ctx.clearRect(0, 0, w, h);//清除畫布
ctx.beginPath();//開始繪製
ctx.arc(posX,posY,radius,0,2*Math.PI);//畫圓
ctx.fillStyle = 'red';//圓的填充顏色
ctx.closePath();//閉合路徑
ctx.fill();//填充

在線預覽:https://codepen.io/jianxiujiu...java

第二步:讓小球動起來

讓小球動起來的原理就是,不斷地改變小球的座標位置並進行重繪。
重繪能夠用setInterval、setTimeout或requestanimationframe。關於它們的區別此處不作詳解,具體能夠參考我好基友的一篇文章:setTimeout 和 requestAnimationFrameweb

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    w = canvas.width,
    h = canvas.height,
    posX = 20, //小球出現的X軸位置
    posY = 20, //小球出現的Y軸位置
    speedX = 3,//小球X軸速度
    speedY = 3,//小球Y軸速度
    radius = 20;//小球半徑

    function ani(){
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        posX += speedX;
        posY += speedY;     
        ctx.beginPath();
        ctx.arc(posX,posY,radius,0,2*Math.PI);
        ctx.fillStyle = 'red';
        ctx.closePath();
        ctx.fill();   
        if(posY < h - radius){ 
            requestAnimFrame(ani) //若是Y軸位置不超過容器高度則一直移動
        }
    }
    ani();

在線預覽:https://codepen.io/jianxiujiu...canvas

第三步:一個小球的碰撞動畫

接下來咱們讓小球動起來,並在畫布四周進行碰撞運動。數組

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    w = canvas.width,
    h = canvas.height,
    posX = 20,
    posY = 20,
    speedX = 2,//小球X軸速度
    speedY = 2,//小球Y軸速度
    startSpeedX = 2,//小球X軸初始速度
    startSpeedY = 2,//小球Y軸初始速度
    radius = 20;//小球半徑

    function ani(){       
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        posX += speedX;
        posY += speedY;
        
        //小球碰壁反彈
        if(posY > h - radius){ 
            speedY*=-1;
        }
        if(posX > w - radius){
            speedX*=-1;  
        }
        if(posY < radius){
            speedY = startSpeedY;
            posY = radius;
        }
        if(posX < radius){
            speedX = startSpeedX;
            posX = radius;
        }
        
        ctx.beginPath();
        ctx.arc(posX,posY,radius,0,2*Math.PI);
        ctx.fillStyle = 'red';
        ctx.closePath();
        ctx.fill();
        requestAnimFrame(ani);
    }

    ani();

在線預覽:https://codepen.io/jianxiujiu...dom

第四步:多個小球的碰撞動畫

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    w = canvas.width,
    h = canvas.height,
    posX,
    posY,
    speedX,
    speedY,
    radius;

    function randomNum(m,n) { //隨機函數
        return Math.floor(Math.random() * (n - m + 1) + m);
    }

    var balls = [] //創建小球數組
    function getBall(){
        for( n = 0; n < 20;n++){ //小球的數量
            radius = randomNum (10,20), //半徑隨機10-20px
            posX = randomNum(radius,w-radius), //X軸位置隨機
            posY = randomNum(radius,h-radius), //Y軸位置隨機
            speedX = randomNum(3,6), //X軸速度隨機
            speedY = randomNum(1,2), //Y軸速度隨機
            startSpeedX = startSpeedX,//記錄X軸起始速度
            startSpeedY = startSpeedY;//記錄X軸起始速度
            fillColor = 'rgb(' + randomNum(0,255) + ',' + randomNum(0,255) + ',' + randomNum(0,255) + ')';//小球顏色隨機
            var ball = {
                radius : radius,
                posX : posX,
                posY : posY,
                speedX : speedX,
                speedY : speedY,
                startSpeedX : startSpeedX, 
                startSpeedY : startSpeedX,
                fillColor : fillColor
            }
            balls.push(ball) //將生成的小球存到數組裏
        }    
    }
    getBall();   
            
    function draw(){     
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var l = balls.length; 
        for(var i = 0;i<l;i++){ //逐一繪製小球動畫
            ctx.beginPath();  
            ballCur = balls[i];
            ballCur.posX += ballCur.speedX;
            ballCur.posY += ballCur.speedY;
            if(ballCur.posY > h - ballCur.radius){
                ballCur.speedY*=-1;
            }
            if(ballCur.posX > w - ballCur.radius){
                ballCur.speedX*=-1;  
            }
            if(ballCur.posY < ballCur.radius){
                ballCur.speedY = startSpeedY;
                ballCur.posY = ballCur.radius;
            }
            if(ballCur.posX < ballCur.radius){
                ballCur.speedX = startSpeedX;
                ballCur.posX = ballCur.radius;
            }            
                               
            ctx.arc(ballCur.posX,ballCur.posY,ballCur.radius,0,2*Math.PI);        
            ctx.fillStyle = ballCur.fillColor;
            ctx.closePath();
            ctx.fill();
           
        }  
        requestAnimFrame(draw);    
    }        
    draw();

在線預覽:https://codepen.io/jianxiujiu...函數

第五步:小球爲自定義圖片的動畫

小球動起來以後,若是但願小球爲圖片,則須要用到Canvas另一個方法:動畫

context.drawImage(image, x, y); //在畫布上定位圖像:
context.drawImage(image, x, y, width, height);//在畫布上定位圖像,並規定圖像的寬度和高度
context.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,destX, destY, destWidth, destHeight);//剪切圖像,並在畫布上定位被剪切的部分

和繪製普通小球不同,繪製圖片球的時候,咱們須要把以前動畫的代碼在加載完圖片以後再執行。而且碰撞的位置也須要進行調整。rest

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    w = canvas.width,
    h = canvas.height,
    ballWidth = 60, //圖片球寬度
    posX,
    posY,
    speedX,
    speedY;
    var img = new Image();
    img.src = 'img/ball.png';
    img.onload = function(){     
        getBall();  
        draw();
    }

    function randomNum(m,n) {
        return Math.floor(Math.random() * (n - m + 1) + m);
    }

    var balls = []
    function getBall(){
        for( n = 0; n < 20;n++){   
            posX = randomNum(ballWidth,w - ballWidth),
            posY = randomNum(ballWidth,h - ballWidth),
            speedX = randomNum(3,7),
            speedY = randomNum(4,8),
            startSpeedX = speedX,
            startSpeedY = speedY;
            ballPicPos = randomNum(0,4)*60; //小球圖片位置隨機
            var ball = {
                posX : posX,
                posY : posY,
                speedX : speedX,
                speedY : speedY,
                startSpeedX : startSpeedX, 
                startSpeedY : startSpeedX,
                ballPicPos : ballPicPos
            }
            balls.push(ball);                  
        }   
    }
     
            
    function draw(){     
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var l = balls.length;
        for(var i = 0;i<l;i++){  
            ballCur = balls[i];
            ballCur.posX += ballCur.speedX;
            ballCur.posY += ballCur.speedY;
            if(ballCur.posY > h - ballWidth){
                ballCur.speedY*=-1;
            }
            if(ballCur.posX > w - ballWidth){
                ballCur.speedX*=-1;  
            }
            if(ballCur.posY < 0){
                ballCur.speedY = startSpeedY;
                ballCur.posY = 0;
            }
            if(ballCur.posX < 0){
                ballCur.speedX = startSpeedX;
                ballCur.posX = 0;
            }                            
           
           ctx.beginPath(); 
           ctx.fillStyle = ctx.drawImage(img,0,ballCur.ballPicPos,ballWidth,ballWidth,ballCur.posX,ballCur.posY,ballWidth,ballWidth);
           ctx.fill();
           ctx.closePath();
           ctx.restore();
           
        }  
        requestAnimFrame(draw);  
    }

線上預覽:https://codepen.io/jianxiujiu...code

PS:小球的圖片位置若是取值大於圖片自己的位置,則IE11下顯示圖片會有BUG。

相關文章
相關標籤/搜索