前言
關於canvas的入門知識,網上有很多成熟的資料,我就不多做介紹啦。
彈跳小球算是一個比較常見的效果,接下來就講講如何在canvas裡實現彈跳小球吧~
首先慣例先看效果圖:
由於視訊轉碼問題,可能有點稍卡,但是在瀏覽器裡看是流暢的噢(。ì _ í。)1.勻減速直線運動
為了方便理解之後的彈跳運動,我們先看看如何在canvas裡實現勻減速直線運動。
我希望達到的目的是:給小球一個初速度,讓小球以這個初速度做直線運動,剛好到達指定的位置時,停止運動。
(1)幾個相關概念
requestAnimationFrame()
做過動畫的人都知道,動畫中經常會用到這個方法。它使用一個回撥函式作為引數,這個回撥函式會在瀏覽器重繪之前呼叫。回撥的次數通常是每秒60次。類比於動畫中的每一幀,每秒60幀,每一幀的時候,都要對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,集合英語和前端知識於一身的公眾號平臺~