關於canvas的入門知識,網上有不少成熟的資料,我就很少作介紹啦。javascript
彈跳小球算是一個比較常見的效果,接下來就講講如何在canvas裏實現彈跳小球吧~html
首先慣例先看效果圖:前端
因爲視頻轉碼問題,可能有點稍卡,可是在瀏覽器裏看是流暢的噢(。ì _ í。)爲了方便理解以後的彈跳運動,咱們先看看如何在canvas裏實現勻減速直線運動。java
我但願達到的目的是:給小球一個初速度,讓小球以這個初速度作直線運動,恰好到達指定的位置時,中止運動。git
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;
//勻減速小球;
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);
}
複製代碼
咱們知道,小球在重力的做用下,掉到地面,若是沒有除去重力的其餘外力做用,速度方向會變成相反,大小不變,可是因爲產生形變和摩擦力等因素,對小球的速度形成必定損失,其速度方向變成相反,大小會比原來小,最後趨於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);
}
}
}
複製代碼
完整的代碼在個人GitHub裏面,有興趣者能夠查閱~
GitHub鏈接:github.com/dy21335/Pra…
歡迎關注公衆號:CSandCatti,集合英語和前端知識於一身的公衆號平臺~