前言
关于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,集合英语和前端知识于一身的公众号平台~