Web-Dev-For-Beginners 太空游戏系列第 4 课作业实践:用矩形相交原理打造自定义碰撞小游戏
本篇技术指南围绕微软开源教程 Web-Dev-For-Beginners「太空游戏」系列第 4 课的课后作业「Explore Collisions」(碰撞探测探索)展开,任务是让学习者运用本课讲解的矩形相交碰撞检测原理,自行创作一个展示多种物体交互方式的迷你游戏。文章将完整拆解作业目标、验收标准与评分细则,并借助本课课程文档与其参考答案源码,给出可复现、可对照评分的设计实现方案,帮助你真正掌握碰撞检测、事件驱动输入与对象生命周期管理。
作业定位:它属于「太空游戏」系列的第 4 课
本仓库是微软发起、面向零基础学习者的 24 课 Web 开发课程。碰撞探测作业位于「构建太空游戏(Build a Space Game)」系列(6-space-game)的第 4 课之后,前置内容依次是画布入门、让元素移动、在画布上绘制物体。第 4 课课程本身(README.md)会带领学习者为飞船加入激光武器并实现完整的碰撞系统,而本作业则要求你脱离示例代码,独立设计一个你自己的碰撞小游戏,用创造性的方式迁移这些知识。
配套工程代码就在本课目录下:
| 目录 | 说明 |
|---|---|
| your-work | 学习者起点代码:只含画布与基本的 GameObject/Hero/Enemy 类,尚无碰撞逻辑,等待你动手实现 |
| solution | 参考答案:完整实现激光射击、碰撞检测、计分与胜负判定 |
提示:两个工程目录的 package.json 都以
npm start启动本地服务器,游戏画布尺寸为1024×768(见 solution/index.html)。
作业要求全解析
作业正文(assignment.md)的核心是:将你在碰撞检测课上学到的知识应用于实践,创建一款自定义迷你游戏,展示不同类型的物体交互方式,通过创造性实现与反复实验来理解碰撞机制。官方给出的评分维度是下面的三件事。
必做:交互式小游戏应当包含四要素
| 要求 | 具体说明 |
|---|---|
| 多个可移动物体 | 可通过键盘或鼠标控制 |
| 碰撞检测系统 | 必须采用本课的**矩形相交(rectangle intersection)**原理 |
| 视觉反馈 | 碰撞发生时要有对象销毁、变色、特效等可感知反馈 |
| 游戏规则 | 让碰撞结果对玩法有意义、有吸引力(胜负、得失分) |
官方创意方向(五选一或自拟)
- 小行星带(Asteroid field):驾驶飞船穿越危险的太空碎片;
- 碰碰车(Bumper cars):创建一个基于物理的碰撞竞技场;
- 陨石防御(Meteor defense):保护地球免受来袭太空岩石的撞击;
- 收集游戏(Collection game):一边收集道具一边躲避障碍;
- 领土控制(Territory control):互相竞争的物体争夺空间。
加分挑战(Bonus challenges)
在完成基础版本后,可逐步加入:碰撞时的粒子特效、不同碰撞类型的音效、基于碰撞结果的计分系统、多种碰撞类型与差异化行为、随时间递增的难度曲线。下文第五、六节会给出这些机制与参考源码的对应实现,可作为迁移蓝本。
评分细则(Rubric):官方到底在考什么
作业文档给出了明确的四级评分表,理解它可以指导你的设计取舍:
| 标准 | 优秀(Exemplary) | 合格(Adequate) | 需改进(Needs Improvement) |
|---|---|---|---|
| 碰撞检测 | 精确实现基于矩形的碰撞检测,支持多种对象类型与高级交互规则 | 基础碰撞检测正确,仅支持简单对象交互 | 碰撞检测存在问题或表现不稳定 |
| 代码质量 | 代码干净、组织良好,类结构合理,变量命名有意义,注释得当 | 代码可运行但组织和文档化有待提高 | 代码难以理解或结构混乱 |
| 用户交互 | 控制响应灵敏、玩法流畅、视觉反馈清晰、机制有吸引力 | 基础控制可用,反馈足够 | 控制不灵敏或令人困惑 |
| 创造力 | 原创概念、独特功能、视觉打磨与创新的碰撞行为 | 标准实现中加入了一些创意元素 | 仅基本功能,无创意增强 |
结合评分表可以反推出设计策略:想拿高分,至少要保证多对象类型共存、类封装清晰、即时且醒目的碰撞反馈,并用加分挑战里的机制凸显原创性。
核心技术一:矩形边界与相交判定(碰撞检测的数学基础)
作业明确要求使用本课的「矩形相交」原理。课程文档把碰撞检测的核心思想拆成两步,这也是你设计任意迷你游戏前必须吃透的数学地基。
1. 用位置 + 尺寸表达边界
每个游戏对象都被视为一个轴对齐矩形(AABB)。只需记录左上角坐标 (x, y) 与宽高,即可推导出四条边。课程给出的标准方法(在 solution/app.js 中即为 GameObject.rectFromGameObject() 的真实实现):
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
换算关系为:顶边 top = y、左边 left = x、底边 bottom = y + height、右边 right = x + width。
2. 分离轴判定:四个「不相交」条件取反
判断两个矩形是否重叠,与其计算重叠区域,不如反证其是否分离:只要矩形 2 完全位于矩形 1 的右侧、左侧、下方或上方任一情形成立,二者必不相交;否则必然碰撞。课程算法(同见 solution/app.js):
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
这条 O(1) 判定只有四次数值比较,非常适合在主循环中对大量对象做实时检测,也是作业中要求掌握的高效实现方式。
核心技术二:对象生命周期管理——「标记删除」而非「即时删除」
作业的「技术实现」要点里包含对象生命周期管理(创建与销毁)。太空游戏示例把这条经验体现得尤为关键:当激光命中敌机、敌机撞上英雄时,双方都需要被移除;但若在遍历数组的循环体中直接删除元素,会导致索引错位甚至崩溃(对应课程自测题「如果立刻删除对象会发生什么」的答案:遍历中途删除会引发崩溃或跳过对象)。
正确范式分两步(参照 solution/app.js 的 updateGameObjects()):
// 第 1 步:碰撞发生时只做「标记」
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
hero.incrementPoints(); // 参考答案额外实现了计分
});
// 第 2 步:本帧结束后统一过滤,安全地在帧间清理
gameObjects = gameObjects.filter((go) => !go.dead);
这种模式让当前帧安全跑完,同时避免死亡对象持续堆积造成内存膨胀。激光到达屏幕顶端时也同样走这条路径:在 solution/app.js 的 Laser 类中,当 this.y <= 0 时置 this.dead = true 并清除自身的 setInterval。
核心技术三:事件驱动输入与对象类设计
作业要求「基于事件的用户输入编程」与「干净的、具备合理类结构的代码组织」。参考答案提供了可直接借鉴的架构范本:
- 事件总线:轻量
EventEmitter(见 solution/app.js),通过on/emit解耦输入、碰撞与渲染逻辑; - 消息常量:
Messages对象统一管理事件名(如KEY_EVENT_SPACE、COLLISION_ENEMY_LASER、COLLISION_ENEMY_HERO),避免字符串散落各处导致拼写错误; - 输入监听:键盘
keyup事件把「按键事实」转为语义化事件发出(solution/app.js),同时用keydown拦截空格与方向键的默认滚动行为; - 类层次:
GameObject基类承载位置、尺寸、贴图与边界计算,Hero、Enemy、Laser各自继承并扩展专属行为(solution/app.js)。你在作业中的代码只要按「基类公共能力 + 子类差异化行为」组织,即符合「干净的类结构」要求。
参考实现还示范了用冷却系统限制开火频率、保持操作手感:Hero.fire() 将激光加入 gameObjects 并把 cooldown 置为 500,由定时器逐步递减到 0,canFire() 仅在冷却归零时返回 true(solution/app.js)。这一设计思想可以直接复用到你的游戏里——比如「陨石防御」需要限制投弹频率,「碰碰车」需要限制加速次数。
实战推演:如何按官方标准做出一款「陨石防御」作业
把上面的机制拼装起来,即可落地为作业要求的完整小游戏。以官方创意方向之一的「陨石防御:保护地球免受来袭太空岩石撞击」为例,逐步设计:
- 对象建模:定义
Earth(静态目标,宽度可参考示例中的 99px 量级)、Meteor(自上而下匀速下降,尺寸、速度随机)、Cannon(键盘←/→控制、可在底部平移)三类,全部继承一个GameObject基类,每个对象实现rectFromGameObject(); - 主循环:以
setInterval(参考示例使用 100ms)驱动每帧updateGameObjects()+ 绘制;updateGameObjects()中按类型过滤出陨石列表与炮弹列表,两两调用intersectRect()做矩形相交测试; - 碰撞事件与规则:炮弹命中陨石 → 双方标记
dead并加 100 分;陨石触底(bottom >= canvas.height)→ 地球生命值减一;生命归零 → 触发失败并结束游戏。注意:陨石与地球也互为碰撞对象,这正好覆盖了评分表中「多种对象类型与高级交互规则」这一优秀档要求; - 视觉反馈:命中瞬间用粒子残影或变色闪烁表现销毁,触底时用红色警示色表现损伤,保证反馈清晰可见;
- 难度曲线:随存活时间逐步缩短陨石生成间隔或加快下落速度,对应加分挑战中的「渐进式难度」;
- 流程闭环:参照参考答案的
endGame(win)与resetGame()(solution/app.js),在胜利/失败后显示提示并可重新开局。
完成主体后,参照作业加分项逐条检查:粒子特效可用短生命周期粒子数组实现,同样走「标记删除 + 帧间过滤」;计分系统只需在事件监听器里维护分数变量并绘制文本(参考答案的 drawPoints() 即为现成范式,见 solution/app.js)。
上手与验证:起点代码、运行与调试
想以仓库提供的骨架快速开始,可按下面步骤操作(以本课 your-work 目录为准):
cd 6-space-game/4-collision-detection/your-work
npm start
随后在浏览器打开 http://localhost:5000,可看到尚未具备碰撞逻辑的初始画布。参考答案位于同级 solution 目录(命令一致,端口同为 5000),可运行对照观察最终行为。
开发过程中的自检清单(对应课程文档的调试建议):
- 打开浏览器 DevTools,在
intersectRect或updateGameObjects处打断点,观察每帧的矩形坐标比较; - 修改激光速度(示例为每 100ms 上移 15px)或陨石下落步长,观察碰撞窗口的变化;
- 调整冷却值(示例为 500ms)与递减节奏(每 200ms 减 100),验证射击手感;
- 用
console.log实时打印碰撞事件,确认事件确实发出且对象被正确标记删除。
仓库为只读示例工程,练习时请复制到本地或 fork 后自行修改运行,文章中所有路径均可直接对照仓库查看源码与素材(游戏贴图位于 solution/assets 与 your-work/assets)。
结论
本作业的真正价值不在于「再写一遍太空游戏」,而在于验证你是否把矩形相交检测从『看得懂』变成了『用得出』。对照评分表自测:碰撞判定是否对多种对象稳定生效?类是否职责分明?操控与反馈是否即时清晰?概念是否有原创亮点?只要用本课提供的 rectFromGameObject() + intersectRect() 分离轴判定范式,配合「标记删除」的生命周期管理、事件驱动输入与类继承结构,再叠加粒子、音效、计分与渐进难度等加分项,你就能交出一份达优秀档的作品——而这些原理同样是你在真实 Web 游戏、交互式可视化乃至前端拖拽交互中长期受用的核心技能。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00