小程序游戏开发:使用Canvas实现简单游戏
关键词:小程序开发、Canvas、2D游戏、游戏循环、碰撞检测
摘要:本文将带您从0到1用微信小程序的Canvas开发一个简单的2D游戏。我们会用"小球吃星星"作为实战案例,从核心概念讲解到代码实现,一步步拆解小程序游戏开发的关键技术点。即使您是刚接触游戏开发的新手,也能通过这篇文章掌握Canvas绘图、游戏循环控制、碰撞检测等核心技能。
背景介绍
目的和范围
随着微信小程序用户突破12亿,基于小程序的轻量级游戏成为开发者的新赛道。本文聚焦"如何用小程序的Canvas API开发简单2D游戏",覆盖从环境搭建到完整游戏实现的全流程,适合想入门小程序游戏开发的开发者。
预期读者
- 有基础的小程序开发者(了解wxml/wxss/js基本语法)
- 对2D游戏开发感兴趣的前端工程师
- 想尝试轻量级游戏开发的独立开发者
文档结构概述
本文采用"概念讲解→原理分析→实战开发"的递进结构:先理解Canvas在小程序中的特性,再掌握游戏循环、碰撞检测等核心机制,最后通过"小球吃星星"案例完整实现一个可运行的游戏。
术语表
核心术语定义
- Canvas:HTML5提供的2D绘图API,小程序中通过
wx.createCanvasContext
调用 - 游戏循环:游戏的"心跳",包含"更新→绘制→等待"三个阶段的无限循环
- 碰撞检测:判断两个游戏对象是否接触的算法(本文用矩形包围盒检测)
- 精灵(Sprite):游戏中的可移动对象(如本文的小球和星星)
缩略词列表
- API:Application Programming Interface(应用程序接口)
- FPS:Frames Per Second(每秒帧数,衡量游戏流畅度)
核心概念与联系
故事引入:画家的"动态画卷"
想象你是一个古代画家,皇帝让你画一幅会动的画卷:里面有一颗会跑的小球,还有会随机出现的星星,小球碰到星星星星就会消失。你会怎么做?
- 首先需要一张能反复修改的"魔法画布"(对应Canvas)
- 然后需要一个"秒表"控制每秒钟画多少张新画(对应游戏循环)
- 最后需要一个"裁判"判断小球有没有碰到星星(对应碰撞检测)
这三个工具,就是我们开发小程序游戏的核心。
核心概念解释(像给小学生讲故事)
1. Canvas:会"擦除重画"的魔法画布
小程序的Canvas就像一块特殊的画布,你可以用它画圆、画矩形、写文字。但和普通画布不同的是,它有"自动擦除"功能——每次调用ctx.clearRect()
就能清空之前的画,然后重新画新内容。就像你用白板笔在白板上画画,画完一页后用板擦一擦,又能画新的一页。
2. 游戏循环:控制"翻页速度"的秒表
我们的游戏画面不是一张静态图,而是由很多张图片快速切换形成的(就像电影的帧)。游戏循环就是控制每秒钟切换多少张图片的机制。小程序中可以用requestAnimationFrame
实现,它会告诉浏览器:“下一次重绘前帮我执行这个函数”,这样就能保证画面流畅。
3. 碰撞检测:判断"有没有碰到"的裁判
游戏里经常需要判断两个物体是否接触(比如小球有没有吃到星星)。最简单的方法是"矩形包围盒检测":给每个物体画一个虚拟的矩形框,只要两个矩形框有重叠,就认为它们碰撞了。就像判断两个盒子有没有叠在一起,只需要看它们的上下左右边是否交叉。
核心概念之间的关系(用小学生能理解的比喻)
-
Canvas和游戏循环的关系:Canvas是画家的画布,游戏循环是画家的秒表。秒表每滴答一次(比如每16ms),画家就擦干净画布(clearRect),然后在画布上画新的内容(小球的新位置、星星的新位置)。
-
游戏循环和碰撞检测的关系:游戏循环是"导演",每次循环都会先让"裁判"(碰撞检测)检查有没有发生碰撞,然后根据结果调整游戏状态(比如星星消失、分数增加),最后再让画家(Canvas)画出新画面。
-
Canvas和碰撞检测的关系:Canvas负责把物体画在正确的位置(记录每个物体的x/y坐标),碰撞检测则用这些坐标计算是否碰撞。就像你在纸上画了两个气球,然后用尺子量它们的位置,判断有没有碰到。
核心概念原理和架构的文本示意图
游戏主循环
├─ 更新阶段(Update)
│ ├─ 处理用户输入(如触摸移动)
│ ├─ 更新物体位置(小球移动、星星移动)
│ └─ 碰撞检测(判断是否吃到星星)
├─ 绘制阶段(Draw)
│ ├─ 清空画布(clearRect)
│ ├─ 绘制背景
│ ├─ 绘制小球
│ └─ 绘制星星
└─ 循环控制(requestAnimationFrame)
Mermaid 流程图
graph TD
A[游戏开始] --> B[进入游戏循环]
B --> C[更新阶段]
C --> D[处理触摸输入]
D --> E[更新物体位置]
E --> F[碰撞检测]
F --> G[更新游戏状态(如分数)]
G --> H[绘制阶段]
H --> I[清空画布]
I --> J[绘制背景]
J --> K[绘制小球]
K --> L[绘制星星]
L --> M[调用requestAnimationFrame]
M --> B
核心算法原理 & 具体操作步骤
1. Canvas基础操作(小程序版)
小程序的Canvas分为"传统Canvas"(canvas
组件)和"自定义组件Canvas"(wx.createCanvasContext
),本文使用更灵活的后者。
关键API说明:
wx.createCanvasContext('canvasId')
:创建画布上下文(相当于拿到画笔)ctx.beginPath()
:开始绘制路径ctx.arc(x, y, r, sAngle, eAngle)
:画圆(x/y圆心坐标,r半径)ctx.fillStyle
:设置填充颜色ctx.fill()
:填充路径ctx.clearRect(x, y, width, height)
:清空指定区域(x/y起点,width/height尺寸)
示例:用Canvas画一个红色小球
// 在Page的onLoad中初始化
onLoad() {
this.ctx = wx.createCanvasContext('gameCanvas'); // 获取画布上下文
this.drawBall(100, 100); // 在(100,100)位置画小球
},
drawBall(x, y) {
this.ctx.beginPath();
this.ctx.arc(x, y, 20, 0, 2 * Math.PI); // 圆心(100,100),半径20
this.ctx.fillStyle = '#FF4D4F'; // 红色
this.ctx.fill();
this.ctx.draw(); // 提交绘制命令
}
2. 游戏循环实现
游戏循环的核心是通过requestAnimationFrame
实现"更新→绘制"的无限循环,目标是保持60FPS(每16ms执行一次)。
代码结构:
startGameLoop() {
// 更新阶段:处理逻辑
this.update();
// 绘制阶段:渲染画面
this.draw();
// 循环调用(告诉浏览器下一次重绘前执行)
this.animationId = requestAnimationFrame(() => this.startGameLoop());
}
// 游戏停止时需要取消循环(避免内存泄漏)
stopGameLoop() {
cancelAnimationFrame(this.animationId);
}
3. 碰撞检测(矩形包围盒算法)
假设小球和星星都是矩形(即使它们画成圆形,也可以用外接矩形检测),判断两个矩形是否相交的条件:
{ 小球左边界 < 星星右边界 小球右边界 > 星星左边界 小球上边界 < 星星下边界 小球下边界 > 星星上边界 \begin{cases} 小球左边界 < 星星右边界 \\ 小球右边界 > 星星左边界 \\ 小球上边界 < 星星下边界 \\ 小球下边界 > 星星上边界 \end{cases} ⎩ ⎨ ⎧小球左边界<星星右边界小球右边界>星星左边界小球上边界<星星下边界小球下边界>星星上边界
代码实现:
// 定义物体的结构(x,y为中心点坐标,width/height为尺寸)
const ball = {
x: 100, y: 100,