我们需要使用到Canvas的方法有:
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…
第二步:让小球动起来
让小球动起来的原理就是,不断地改变小球的坐标位置并进行重绘。
重绘可以用setInterval、setTimeout或requestanimationframe。关于它们的区别此处不做详解,具体可以参考我好基友的一篇文章:setTimeout 和 requestAnimationFrame
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…
第三步:一个小球的碰撞动画
接下来我们让小球动起来,并在画布四周进行碰撞运动。
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…
第四步:多个小球的碰撞动画
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);//剪切图像,并在画布上定位被剪切的部分
和绘制普通小球不一样,绘制图片球的时候,我们需要把之前动画的代码在加载完图片之后再执行。并且碰撞的位置也需要进行调整。
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…
PS:小球的图片位置如果取值大于图片本身的位置,则IE11下显示图片会有BUG。