html5Canvas绘图教程:从基础图形到动画效果,附小游戏开发案例

admin HTML教程 3


想在网页上画点好玩的图形却不知道咋下手?看别人用 Canvas 做的小游戏羡慕得不行,自己打开编辑器却连个方块都画不出来?不少新手朋友跟我吐槽,Canvas 绘图看着酷炫,实际学起来全是坎儿 —— 坐标搞反、图形不显示、动画卡顿,问题一箩筐。其实啊,Canvas 没那么难,就像小时候在作业本上画画,先学会画直线圆圈,再练组合动画,循序渐进就能上手。今天兔子哥就从基础图形讲到动画效果,最后带大家做个简单的打方块小游戏,代码全是新手能看懂的大白话,跟着敲,你也能画出会动的图形!

一、先搞懂 Canvas:网页上的 “数字画板”,这两步先做好


Q:“Canvas 到底是啥?跟普通图片有啥不一样?”
A:Canvas 就是网页上的一块 “可绘图区域”,你可以用 JavaScript 在上面画图形、写文字、做动画,甚至搞小游戏。它跟图片最大的区别是:Canvas 的内容是用代码画出来的,能实时修改,比如让图形动起来、变颜色,这可是静态图片做不到的。

1. 准备画布:先在 HTML 里 “铺好纸”


想画画得先有画布,在 HTML 里用标签创建,就像在网页上铺了张纸:
html
<canvas id="myCanvas" width="600" height="400" style="border: 1px solid #000;">canvas>

避坑点:画布大小别用 CSS 设置!上面代码里的widthheight是画布实际尺寸,要是用 CSS 的width:600px,会把画布拉伸变形,画的圆可能变成椭圆。新手常犯这错,画出来的图形歪歪扭扭,就是因为没搞对尺寸。

2. 获取画笔:用 JavaScript “拿起笔”


有了画布还得有画笔,在 JS 里通过 “上下文”(context)操作绘图,就像拿起不同的画笔:
javascript
// 获取画布元素const canvas = document.getElementById('myCanvas');// 获取2D绘图上下文(这就是我们的“画笔”)const ctx = canvas.getContext('2d');

这两行代码是所有 Canvas 绘图的基础,少了它们,后面啥也画不出来。新手一定要记住:先获取 canvas 元素,再用getContext('2d')拿画笔,不然图形肯定不显示。

二、基础图形绘制:从点线面开始,这几个方法必学


Canvas 绘图就像搭积木,先学会画基本图形,再组合成复杂图案。

1. 画矩形:最简单的图形,三行代码搞定


fillRect画填充矩形,strokeRect画边框矩形,参数都是 “x 坐标、y 坐标、宽度、高度”:
javascript
// 填充矩形(带颜色的方块)ctx.fillStyle = 'red'; // 先设置填充颜色ctx.fillRect(50, 50, 100, 80); // 从(50,50)开始,画100宽80高的红方块// 边框矩形(空心方块)ctx.strokeStyle = 'blue'; // 设置边框颜色ctx.lineWidth = 3; // 设置线宽ctx.strokeRect(200, 50, 100, 80); // 画蓝色边框方块

Q:“坐标是咋算的?为啥我画的图形跑角落去了?”
A:Canvas 的坐标原点在左上角,x 轴向右增大,y 轴向增大(跟数学里的 y 轴相反)。比如(0,0)是左上角,(600,400)是我们画布的右下角,新手常搞反 y 轴方向,画的图形位置总不对。

2. 画圆形和弧线:用 arc 方法,参数有点多但不难记


画圆用arc方法,参数是 “圆心 x、圆心 y、半径、开始角度、结束角度、是否逆时针”:
javascript
ctx.beginPath(); // 开始新路径(相当于换张纸画)ctx.arc(350, 100, 50, 0, Math.PI * 2, false); // 画完整圆形ctx.fillStyle = 'green';ctx.fill(); // 填充颜色// 画半圆(弧线)ctx.beginPath(); // 一定要重新开始路径,不然会连上前一个图形ctx.arc(500, 100, 50, 0, Math.PI, false); // 从0到π弧度(上半圆)ctx.strokeStyle = 'purple';ctx.stroke(); // 描边

避坑点:画多个图形必须用beginPath()!不然图形会自动连起来,线条乱成一团。之前有学员画了圆又画弧线,没加beginPath,结果两个图形被一条线连起来,看着特奇怪。

3. 画路径和文字:组合图形、加说明


用路径可以画任意形状,比如三角形;用fillText可以在画布上写字:
javascript
// 画三角形(路径组合)ctx.beginPath();ctx.moveTo(100, 200); // 起点移到(100,200)ctx.lineTo(150, 300); // 画到(150,300)ctx.lineTo(50, 300); // 画到(50,300)ctx.closePath(); // 闭合路径(回到起点)ctx.fillStyle = 'yellow';ctx.fill();// 写文字ctx.font = '20px 微软雅黑'; // 设置字体和大小ctx.fillStyle = 'black';ctx.fillText('这是一个三角形', 100, 350); // 在(100,350)位置写字

三、动画效果:让图形 “动起来”,核心就这两步


静态图形看久了没意思,给它们加动画才好玩。Canvas 动画原理很简单:不断清除画布、重画图形,视觉上就像动起来了。

1. 移动的小球:基础动画案例


让小球从左往右移动,代码这样写:
javascript
let x = 50; // 小球初始x坐标function draw() {// 第一步:清除画布(不然会有拖影)ctx.clearRect(0, 0, canvas.width, canvas.height);// 第二步:画小球ctx.beginPath();ctx.arc(x, 200, 30, 0, Math.PI * 2);ctx.fillStyle = 'orange';ctx.fill();// 第三步:更新位置(每帧x加2)x += 2;// 碰到边界反弹if (x > canvas.width - 30 || x < 30) {x = x > canvas.width - 30 ? canvas.width - 30 : 30; // 简单反弹处理}// 循环调用draw函数,实现动画(requestAnimationFrame比setInterval更流畅)requestAnimationFrame(draw);}draw(); // 启动动画

避坑点:一定要清除画布!clearRect能擦掉上一帧的内容,不然小球移动会留下一串影子。动画用requestAnimationFramesetInterval好,它会跟屏幕刷新率同步,动画更流畅,不容易卡顿。

2. 鼠标跟随:让图形跟着鼠标动


想让图形跟着鼠标跑?监听mousemove事件获取鼠标坐标就行:
javascript
let mouseX = 0, mouseY = 0;// 监听鼠标移动事件canvas.addEventListener('mousemove', function(e) {// 获取鼠标在画布上的坐标(减去画布偏移量)const rect = canvas.getBoundingClientRect();mouseX = e.clientX - rect.left;mouseY = e.clientY - rect.top;});function draw() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 画跟随鼠标的方块ctx.fillStyle = 'pink';ctx.fillRect(mouseX - 25, mouseY - 25, 50, 50); // 让鼠标在方块中心requestAnimationFrame(draw);}draw();

这里用getBoundingClientRect获取画布位置,避免因为网页滚动导致坐标不准,新手容易忽略这个,结果鼠标和图形对不上。

四、小游戏开发:打方块小游戏,完整案例详解


学会基础动画,就能尝试做简单小游戏了。咱做个 “打方块” 游戏:用挡板接小球,碰到方块消除。

1. 游戏元素准备:定义挡板、小球、方块


javascript
// 挡板const paddle = {x: canvas.width / 2 - 50,y: canvas.height - 30,width: 100,height: 15,speed: 8};// 小球const ball = {x: canvas.width / 2,y: canvas.height - 50,radius: 10,dx: 4, // x方向速度dy: -4 // y方向速度(向上)};// 方块数组const bricks = [];const brickRow = 3; // 3行方块const brickCol = 5; // 5列方块for (let i = 0; i < brickCol; i++) {bricks[i] = [];for (let j = 0; j < brickRow; j++) {const brickX = i * (100 + 20) + 30; // 间距20,左边距30const brickY = j * (30 + 20) + 50; // 上边距50bricks[i][j] = { x: brickX, y: brickY, width: 100, height: 30, alive: true };}}

2. 绘制游戏元素和控制逻辑


javascript
// 绘制挡板function drawPaddle() {ctx.fillStyle = 'blue';ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);}// 绘制小球function drawBall() {ctx.beginPath();ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);ctx.fillStyle = 'red';ctx.fill();}// 绘制方块function drawBricks() {for (let i = 0; i < brickCol; i++) {for (let j = 0; j < brickRow; j++) {const brick = bricks[i][j];if (brick.alive) { // 只画活着的方块ctx.fillStyle = 'green';ctx.fillRect(brick.x, brick.y, brick.width, brick.height);}}}}// 键盘控制挡板移动document.addEventListener('keydown', function(e) {if (e.key === 'ArrowRight' && paddle.x < canvas.width - paddle.width) {paddle.x += paddle.speed; // 右移} else if (e.key === 'ArrowLeft' && paddle.x > 0) {paddle.x -= paddle.speed; // 左移}});// 碰撞检测(小球碰方块)function checkCollision() {for (let i = 0; i < brickCol; i++) {for (let j = 0; j < brickRow; j++) {const brick = bricks[i][j];if (brick.alive &&ball.x > brick.x && ball.x < brick.x + brick.width &&ball.y > brick.y && ball.y < brick.y + brick.height) {ball.dy = -ball.dy; // 反弹brick.alive = false; // 消除方块}}}// 碰墙壁反弹(上下左右)if (ball.x < ball.radius || ball.x > canvas.width - ball.radius) ball.dx = -ball.dx;if (ball.y < ball.radius) ball.dy = -ball.dy;// 碰挡板反弹if (ball.y > paddle.y - ball.radius &&ball.x > paddle.x && ball.x < paddle.x + paddle.width) {ball.dy = -ball.dy;}}// 游戏主循环function gameLoop() {ctx.clearRect(0, 0, canvas.width, canvas.height);drawPaddle();drawBall();drawBricks();checkCollision();// 更新小球位置ball.x += ball.dx;ball.y += ball.dy;requestAnimationFrame(gameLoop);}gameLoop(); // 开始游戏

这个小游戏包含了绘图、动画、交互、碰撞检测,新手可以在此基础上添加计分、生命值功能,慢慢扩展。

问答时间:新手常问的 3 个问题


Q:“为啥我画的图形不显示?排查半天没头绪。”
A:先检查这几点:1. 画布widthheight有没有设置;2. 有没有获取getContext('2d');3. 绘图方法前有没有设置fillStylestrokeStyle(默认透明,可能看不见);4. 路径是否闭合或调用了fill()/stroke()
Q:“动画卡顿怎么办?尤其是图形多的时候。”
A:减少不必要的绘图操作,比如只重画变化的部分;用requestAnimationFrame代替setInterval;复杂图形可以用图片代替绘制。
Q:“想画更复杂的图形,比如人物,有啥技巧?”
A:复杂图形可以拆成基础图形组合,或者用路径工具一点点画;也可以先在纸上画好轮廓,再对照着写坐标。多练多试,熟了就快了。
兔子哥觉得,Canvas 绘图的乐趣在于 “所见即所得”—— 敲几行代码,屏幕上就出现图形,动起来的瞬间特别有成就感。新手别一开始就追求复杂效果,先把矩形、圆形画熟练,再练动画,最后尝试小游戏,一步一步来。
其实很多厉害的 Canvas 效果,底层都是简单的图形和动画原理,就像搭积木,简单零件能拼出复杂造型。遇到问题别慌,多用浏览器调试工具(F12)看坐标、查变量,慢慢就能摸透规律。现在就打开编辑器,从画一个移动的小球开始,你会发现 Canvas 绘图真的很好玩!

标签: .getElementById 循序渐进

发布评论 0条评论)

  • Refresh code

还木有评论哦,快来抢沙发吧~