奇妙的canvas:彈跳小球

前言

關於canvas的入門知識,網上有不少成熟的資料,我就很少作介紹啦。javascript

彈跳小球算是一個比較常見的效果,接下來就講講如何在canvas裏實現彈跳小球吧~html

首先慣例先看效果圖:前端

因爲視頻轉碼問題,可能有點稍卡,可是在瀏覽器裏看是流暢的噢(。ì _ í。)

1.勻減速直線運動

爲了方便理解以後的彈跳運動,咱們先看看如何在canvas裏實現勻減速直線運動。java

我但願達到的目的是:給小球一個初速度,讓小球以這個初速度作直線運動,恰好到達指定的位置時,中止運動。git

(1)幾個相關概念

requestAnimationFrame()github

作過動畫的人都知道,動畫中常常會用到這個方法。它使用一個回調函數做爲參數,這個回調函數會在瀏覽器重繪以前調用。回調的次數一般是每秒60次。類比於動畫中的每一幀,每秒60幀,每一幀的時候,都要對canvas的畫布進行擦除與重繪。canvas

結合到勻減速運動,也就是說,我要知道每一幀,這個小球的座標位置。瀏覽器

另外值得一提的是,canvas的座標長介個樣子:函數

幾個物理概念動畫

在這裏,我把單位時間定爲每一幀,單位距離定爲每個像素;

  • 速度v表示的是每單位時間內,移動的距離;

  • 加速度a表示每單位時間內,速度v的改變值;

我先指定這個小球只沿着x軸運動,運動距離是canvas的寬度,因此咱們的問題是:

(1)如何讓小球恰好在到達canvas邊界時,速度遞減到0?
​ 那就要求加速度a,由物理公式咱們能夠求出a=v^2/2s。

(2)在每一幀怎麼更新小球位置?

​ 在每一幀都要更新速度v = v + a,和小球的x軸座標x = x+v;

(2)代碼片斷

//勻減速小球;
    function Ball(radius, x, y, v){
        this.radius = radius;
        this.x = x;
        this.y = y;
        this.v = v;
        this.a = ((Math.pow(v,2)/(2*(canvas.width-x))))*(-1);
    }
    //繪製勻減速小球;
    function drawBall(){
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = '#fff';
        ctx.beginPath();
		//更新
        ball.v += ball.a;
        ball.x += ball.v;

        ball.x = (ball.x + ball.radius > canvas.width) ? (canvas.width - ball.radius) : ball.x;

        ctx.arc(ball.x, canvas.height/2, ball.radius, 0, 2 * Math.PI, true);
        ctx.fill();

        stop = ball.x + ball.radius >= canvas.width ? cancelAnimationFrame(stop) : requestAnimationFrame(drawBall);
    }
複製代碼

2. 彈跳運動

咱們知道,小球在重力的做用下,掉到地面,若是沒有除去重力的其餘外力做用,速度方向會變成相反,大小不變,可是因爲產生形變和摩擦力等因素,對小球的速度形成必定損失,其速度方向變成相反,大小會比原來小,最後趨於0。

其實彈跳運動的實現也很簡單,給他一個重力加速度,在它觸碰到底部時,能夠經過設置一個 -1~0的damping 值,讓小球每次接觸到底部時,v = v * damping,這樣通過幾個彈跳,v就會逐漸趨於0。

代碼片斷

//彈跳小球;
    function BcBall(radius, x, y, v){
        this.radius = radius;
        this.x = x;
        this.y = y;
        this.v = v;
        //設置重力加速度與損失比例
        this.gravity = 0.5;
        this.damping = -0.8;
    }
 //繪製彈性小球;
    var preV = 0;   //記錄前一次速度

    function drawBcBall() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = '#fff';
        ctx.beginPath();

        ball.v += ball.gravity;
        ball.y += ball.v;
        preV = ball.v;

        ctx.arc(canvas.width/2, ball.y, ball.radius, 0, 2 * Math.PI, true);
        ctx.fill();
        stop = requestAnimationFrame(drawBcBall);

        if(ball.y + ball.radius >= canvas.height){
            ball.y = canvas.height - ball.radius;
            ball.v *= ball.damping;
            
            if(Math.abs(preV - ball.v) < 0.5){
                cancelAnimationFrame(stop);
            }
        }
    }
複製代碼

Last

完整的代碼在個人GitHub裏面,有興趣者能夠查閱~

GitHub鏈接:github.com/dy21335/Pra…

撒花~

歡迎關注公衆號:CSandCatti,集合英語和前端知識於一身的公衆號平臺~

相關文章
相關標籤/搜索