1、新建画布
canvas首先是空白的,我们首先设置canvas的宽高,并找到渲染上下文
<body> <!-- 新建canvas元素 --> <canvas id="canvas"></canvas> </body>
window.onload = () => { // 获取canvasDom const canvas = document.getElementById("canvas"); // 手动设置宽高 canvas.width = 800; canvas.height = 800; // 获取上下文 const ctx = canvas.getContext("2d"); };
2、绘制边框
此时页面已经可以看到画布了,我们可以更明显的一些绘制一个边框
window.onload = () => { ..... // 获取canvas上下文 const ctx = canvas.getContext("2d"); // 绘制边框 renderBorder(ctx); }; function renderBorder(ctx) { // 首先获取画布的宽高 const width = ctx.canvas.width; const height = ctx.canvas.height; ctx.beginPath(); // 开始一个新的路径 ctx.moveTo(0, 0); // 将路径的起始点移动到左上角 ctx.lineTo(width, 0); // 使用直线连接到右上角(并不绘制) ctx.lineTo(width, height); // ...右下角 ctx.lineTo(0, height); // ...左下角 ctx.closePath(); // 结束一个新的路径 ctx.stroke(); // 绘制当前已知路径 }
3、绘制球
此时我们已经可以看到边框了,首先需要新建一个“球”对象,球对象有如下一些属性,再实现如何绘制这个“球”对象,这里涉及到canvas绘制圆弧路径的方法,比较特殊的这里是弧度
void ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
x:圆弧中心点x轴坐标
y: 圆弧中心点y轴坐标
radius: 半径
startAngle:圆弧起始点
endAngle: 圆弧结束点
anticlockwis(可选):Boolean类型,如果为true,则逆时针方向绘制,反之,顺时针方向绘制
window.onload = () => { ..... // 绘制球 let ball = { x: 0, // 当前x轴坐标 y: 0, // 当前y轴坐标 radius: 10, // 半径 g: 0.1, // 重力加速度 vx: 8, // x轴移动速度 vy: 4, // y轴移动速度 color: "blue", // 颜色 }; renderBall(ctx, ball); }; // 绘制一个球 function renderBall(ctx, ball) { const x = ball.x + ball.radius; // 圆弧中心(圆心)的 x 轴坐标。 const y = ball.y + ball.radius; // 圆弧中心(圆心)的 y 轴坐标。 const radius = ball.radius; // 半径 const startAngle = 0; // 圆弧的起始点 const endAngle = 2 * Math.PI; // 圆弧的结束点 ctx.beginPath(); // 开始一个新的路径 ctx.arc(x, y, radius, startAngle, endAngle); ctx.closePath(); // 结束一个新的路径 ctx.fillStyle = ball.color; // 颜色 ctx.fill(); // 填充 }
4、让球动起来
这是我们已经绘制了一个球,接下来根据球在x轴与y轴上的速度移动起来,并给y轴加上重力加速度,这里需要注意的是每次绘制都需要重新清除一下画布,canvas动画本质就是每次都清除一遍画布重新绘画
window.onload = () => { // ..... let ball = { x: 0, // 当前x轴坐标 y: 0, // 当前y轴坐标 radius: 10, // 半径 g: 0.1, // 重力加速度 vx: 8, // x轴移动速度 vy: 4, // y轴移动速度 color: "blue", // 颜色 }; setInterval(() => { // 先将之前绘制的擦除 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 绘制边框 renderBorder(ctx); // 绘制球 renderBall(ctx, ball); ball = updateBall(ball); }, 20); } // 更新ball function updateBall(ball) { ball.x += ball.vx; ball.y += ball.vy; ball.vy += ball.g; return ball; }
5、优化
现在小球已经可以动起来了,再优化一下updateBall函数,真实一点,例如当小球调到边框的时候可以反弹回来,且每次反弹都会让加速度变慢
function updateBall(ctx, ball) { const width = ctx.canvas.width; const height = ctx.canvas.height; ball.x += ball.vx; ball.y += ball.vy; ball.vy += ball.g; if (ball.y + ball.radius >= height) { ball.y = height - ball.radius; ball.vy = -ball.vy * 0.5; } if (ball.y + ball.radius <= 0) { ball.y = 0 - ball.radius; ball.vy = -ball.vy * 0.5; } if (ball.x + ball.radius >= width) { ball.x = width - ball.radius; ball.vx = -ball.vx * 0.5; } if (ball.x + ball.radius <= 0) { ball.x = 0 - ball.radius; ball.vx = -ball.vx * 0.5; } return ball; }
整体代码
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Canvas小球</title> </head> <body> <!-- 新建canvas元素 --> <canvas id="canvas"></canvas> </body> <script> window.onload = () => { // 获取canvasDom const canvas = document.getElementById("canvas"); // 手动设置宽高 canvas.width = 800; canvas.height = 800; // 获取canvas上下文 const ctx = canvas.getContext("2d"); let ball = { x: 0, // 当前x轴坐标 y: 0, // 当前y轴坐标 radius: 10, // 半径 g: 0.1, // 重力加速度 vx: 8, // x轴移动速度 vy: 4, // y轴移动速度 color: "blue", // 颜色 }; setInterval(() => { // 先将之前绘制的擦除 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 绘制边框 renderBorder(ctx); // 绘制球 renderBall(ctx, ball); ball = updateBall(ctx, ball); }, 20); }; // 绘制边框 function renderBorder(ctx) { // 首先获取画布的宽高 const width = ctx.canvas.width; const height = ctx.canvas.height; ctx.beginPath(); // 开始一个新的路径 ctx.moveTo(0, 0); // 将路径的起始点移动到左上角 ctx.lineTo(width, 0); // 使用直线连接到右上角(并不绘制) ctx.lineTo(width, height); // ...右下角 ctx.lineTo(0, height); // ...左下角 ctx.closePath(); // 结束一个新的路径 ctx.stroke(); // 绘制当前已知路径 } // 绘制一个球 function renderBall(ctx, ball) { const x = ball.x + ball.radius; // 圆弧中心(圆心)的 x 轴坐标。 const y = ball.y + ball.radius; // 圆弧中心(圆心)的 y 轴坐标。 const radius = ball.radius; // 半径 const startAngle = 0; // 圆弧的起始点 const endAngle = 2 * Math.PI; // 圆弧的结束点 ctx.beginPath(); // 开始一个新的路径 ctx.arc(x, y, radius, startAngle, endAngle); ctx.closePath(); // 结束一个新的路径 ctx.fillStyle = ball.color; // 颜色 ctx.fill(); // 填充 } // 更新ball function updateBall(ctx, ball) { const width = ctx.canvas.width; const height = ctx.canvas.height; ball.x += ball.vx; ball.y += ball.vy; ball.vy += ball.g; if (ball.y + ball.radius >= height) { ball.y = height - ball.radius; ball.vy = -ball.vy * 0.5; } if (ball.y + ball.radius <= 0) { ball.y = 0 - ball.radius; ball.vy = -ball.vy * 0.5; } if (ball.x + ball.radius >= width) { ball.x = width - ball.radius; ball.vx = -ball.vx * 0.5; } if (ball.x + ball.radius <= 0) { ball.x = 0 - ball.radius; ball.vx = -ball.vx * 0.5; } return ball; } </script> </html>