Web-Dev-For-Beginners 太空游戏碰撞检测实战:用矩形相交原理打造你的自定义迷你游戏
本篇技术指南围绕 Web-Dev-For-Beginners 课程「太空游戏」第 4 课《Adding A Laser and Detect Collisions》的课后作业展开,核心任务是在理解矩形边界与相交判定算法的基础上,独立设计并实现一个包含多种对象交互、具备完整游戏规则的自定义碰撞检测迷你游戏。读完本文,你将掌握基于 rectFromGameObject / intersectRect 的矩形碰撞检测落地方法、事件驱动输入架构、对象生命周期管理(标记删除),并能参照仓库中的官方参考实现完成从需求分析、代码组织到评分自查的全流程实践。
一、作业背景:从理论到创作的实践闭环
本作业承接第 4 课的核心知识——在太空游戏中为英雄飞船添加激光武器并实现碰撞检测。课程用矩形近似所有游戏对象(类似空管系统用简化几何形状追踪飞机),通过「分离测试」判断两个矩形是否相交,这套算法同样被广泛用于物理模拟与交互式 Web 界面。
本课完整的讲义内容位于 6-space-game/4-collision-detection/README.md,英文原版作业见 6-space-game/4-collision-detection/assignment.md。作业要求你把学到的碰撞检测知识迁移到全新场景:不局限于太空射击,而是创造性地实现一个展示不同类型对象交互的迷你游戏,通过亲自动手加深对碰撞机制的理解。
二、核心原理回顾:两个你必须吃透的函数
动手创作前,先复习第 4 课的两个核心算法,它们是你作业的技术基石。
1. 用矩形边界描述游戏对象
每个游戏对象只需四组数据即可定义碰撞区域:位置 (x, y) 与尺寸 (width, height),由此推导出四条边:
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
该方法的官方实现位于 6-space-game/4-collision-detection/solution/app.js,作为 GameObject 基类方法,所有子类(Hero、Enemy、Laser)都能复用这套标准化接口。
2. 分离测试判定相交
判断两个矩形是否相交,不需要计算重叠面积,只需检查四种「分离」条件是否成立:
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
四种分离情形分别是:矩形 2 完全在矩形 1 的右边、左边、下边或上边。只要其中任意一种成立,两者必然不相交;反之(取反后返回 true)即发生碰撞。相比直接计算交叠区域,分离测试只需最多 4 次比较,性能优异,是实时游戏循环中的高效选择(参考实现见 solution/app.js)。
三、项目需求:四项硬性要求
作业要求创建一个小型交互式游戏,必须满足:
- 多个可移动对象:支持通过键盘或鼠标控制(移动的对象不必全部可操控,但至少核心角色要能响应输入);
- 碰撞检测系统:使用本课矩形相交原理实现;
- 碰撞时的视觉反馈:对象销毁、颜色变化、特效等,让玩家「看见」碰撞发生;
- 游戏规则:让碰撞产生意义——比如击中得分、碰到扣命、碰撞导致失败等,使玩法有目标、有张力。
四、创作方向建议:五个可直接开局的场景
如果你缺少灵感,作业提供了五个经过验证的场景原型,任选其一即可快速起步:
| 场景 | 核心玩法 | 碰撞双方 |
|---|---|---|
| 小行星带(Asteroid field) | 驾驶飞船穿越危险太空碎片 | 飞船 ↔ 小行星 |
| 碰碰车(Bumper cars) | 基于物理的碰撞竞技场 | 车辆 ↔ 车辆 |
| 陨石防御(Meteor defense) | 保护地球免受太空岩石袭击 | 炮弹 ↔ 陨石 |
| 收集游戏(Collection game) | 收集物品同时躲避障碍 | 玩家 ↔ 道具 / 玩家 ↔ 障碍 |
| 领土控制(Territory control) | 竞争对象争夺空间地盘 | 对象 ↔ 对象 |
这些场景的共同点在于:都能充分展现「不同类型的对象交互」,且规则设计天然围绕碰撞展开。建议优先选择你能完整实现四项需求、又留有创意发挥空间的方案。
五、技术实现要求:作业评分的技术基线
作业明确要求解决方案必须体现以下四项技术能力,这也是评审「技术分」的衡量标准:
- 正确使用基于矩形的碰撞检测:所有碰撞判定都应通过
intersectRect完成,而不是依赖像素级检测或距离估算; - 事件驱动编程处理用户输入:键盘/鼠标事件应通过事件系统分发,而不是在游戏主循环里轮询按键状态;
- 对象生命周期管理(创建与销毁):对象创建(如发射子弹、生成敌人)与销毁(碰撞后移除)都要安全、可追踪;
- 清晰的代码组织与合适的类结构:建议采用基类 + 子类的继承设计,职责分明。
源码佐证:官方实现中的事件驱动架构
仓库官方参考实现 solution/app.js 展示了这套架构的标准写法,你可直接借鉴:
① 轻量事件总线 EventEmitter(app.js):用 on() 注册监听器、emit() 触发事件,实现输入、碰撞、游戏状态之间的解耦通信。
② 按键输入通过 keyup 事件发射消息(app.js):方向键对应 KEY_EVENT_UP/DOWN/LEFT/RIGHT,空格键(keyCode === 32)对应 KEY_EVENT_SPACE,回车键对应 KEY_EVENT_ENTER。注意 keydown 阶段用 preventDefault() 阻止方向键与空格滚动页面(app.js),这是浏览器游戏必备的细节。
③ initGame() 中注册各类事件监听器(app.js):例如空格键事件中先调用 hero.canFire() 检查冷却,满足条件才执行 hero.fire();激光命中敌人的事件中,将两个对象同时标记为 dead = true 并加分。
④ 主循环调用 updateGameObjects() 完成碰撞检测与对象清理(app.js):先按类型过滤出 Enemy 与 Laser 列表,再做两两相交测试,命中即发射事件,最后统一 filter 掉死亡对象。
生命周期管理:先标记、后删除
作业特别强调对象销毁的安全性。官方实现的正确姿势是:碰撞发生时只把对象的 dead 标记为 true,不在循环遍历中途直接删除数组元素(否则可能导致遍历错乱甚至崩溃);待本帧碰撞测试全部结束后,再用 gameObjects = gameObjects.filter(go => !go.dead) 一次性剔除死亡对象。这样既保证当前帧稳定完成,又防止死亡对象长期驻留内存造成膨胀。Laser 类中 this.dead = true; clearInterval(id); 的写法(app.js)是「飞出屏幕自动销毁」的典型实现,你的迷你游戏同样需要这类边界处理(如障碍出界回收)。
六、加分挑战:让作品从合格走向优秀
完成基础需求后,作业给出了五个可选的增强方向,每一项都能显著提升作品完成度:
- 粒子特效:碰撞发生时迸发粒子爆炸效果;
- 音效:为不同类型的碰撞配上不同的声音反馈;
- 计分系统:基于碰撞结果(击中/躲避/占领)累加分数;
- 多类型碰撞:不同对象对碰撞做出差异化响应(如道具加血、障碍扣命);
- 渐进难度:难度随时间提升(对象速度加快、生成频率提高、障碍增多)。
这些增强点与评分标准中「Exemplary(优秀)」档的描述一一对应:精细的交互规则、清晰的视觉反馈、创新的碰撞行为,都是拉开差距的关键。
七、评分标准(Rubric):逐项对照自查
作业附带的评分表是官方评审依据,建议开发过程中对照自查:
| 标准 | 优秀(Exemplary) | 合格(Adequate) | 需改进(Needs Improvement) |
|---|---|---|---|
| 碰撞检测 | 对多种对象类型实现精确的基于矩形的碰撞检测,并配有精细的交互规则 | 基础碰撞检测正常工作,对象交互简单 | 碰撞检测存在问题或运行不稳定 |
| 代码质量 | 代码整洁、组织良好,类结构合理、变量命名有意义、注释得当 | 代码可运行,但组织或注释可以更好 | 代码难以理解或结构混乱 |
| 用户交互 | 控件响应灵敏,游戏体验流畅,视觉反馈清晰,机制有趣 | 基础操控可用,反馈尚可 | 控件无响应或令人困惑 |
| 创造力 | 概念原创、特色鲜明,视觉精致,碰撞行为有创新 | 实现常规,带有部分创意元素 | 仅有基础功能,无创意增强 |
对照上表可以设计出你的验收清单:碰撞是否覆盖了至少两类对象组合?代码是否分层(渲染、逻辑、输入分离)?控制是否流畅且带反馈?玩法是否有让人眼前一亮的创意点?
八、参考实现的运行与演练路径
仓库同时提供了练习起点与完整答案,适合边做边对照:
- 练习起点:6-space-game/4-collision-detection/your-work/——内含
index.html、app.js、package.json及assets/精灵图(enemyShip.png、player.png、laserRed.png、life.png),结构已就绪,只等你补上碰撞功能; - 完整答案:6-space-game/4-collision-detection/solution/——官方实现,
app.js中已包含 Hero/Enemy/Laser 三大类、冷却系统、生命与分数逻辑。
两者 package.json 均以 npx http-server -c-1 -p 5000 启动本地服务(见 solution/package.json)。运行方式:
cd 6-space-game/4-collision-detection/solution # 或 your-work
npm start
然后浏览器访问 http://localhost:5000 即可体验:方向键移动英雄,空格键发射激光,激光命中敌机双方销毁并加分;敌机与英雄相撞时敌机销毁、英雄损失一条生命(decrementLife),生命归零即失败。这段可玩性验证流程同样适用于你的自定义迷你游戏——先用官方答案跑通「碰撞产生 → 事件触发 → 对象清理 → 状态更新」的完整链路,再迁移到你自己的场景中。
九、总结
本次作业的真正价值不在于复刻某个模板,而在于完成一次「原理 → 设计 → 实现 → 验收」的完整工程演练:用矩形边界与分离测试解决碰撞判定,用事件驱动解耦输入与响应,用「标记后删除」保障生命周期安全,再用评分表量化质量。完成它之后,这些碰撞检测技能可以直接迁移到交互式界面、拖拽操作、触摸手势识别乃至机器人路径规划等更广阔的领域——这也是 Web-Dev-For-Beginners 太空游戏系列(总览见 6-space-game/README.md)想传递的核心能力。
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 StartedRust4.22 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python400
cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端TypeScript2 K146
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python48467
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go20843
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java34451