ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

HTML5重写《黄金矿工》:网页游戏源码解析与改造指南

2026/9/15 17:17:28 拓冰建站 浏览量
HTML5重写《黄金矿工》:网页游戏源码解析与改造指南 简介仿《黄金矿工》的 HTML5 网页小游戏完整源码使用 HTML、CSS 与原生 JavaScript 实现打开入口页面即可体验完整的抓取、拉拽、挖掘与计分玩法无需后端服务或复杂构建工具适合 Web 前端初学者研究游戏循环、碰撞检测与键盘鼠标交互等核心知识点也可作为个人网站或游戏站点的休闲模块直接集成或用作课程设计与前端练手项目。压缩包共 203 个文件整体仅 7.66MB包含 156 个 PNG 图片、21 个 M4A 与 21 个 OGG 音频、4 个 JS 脚本和 1 个 HTML 文件图片覆盖角色、金块、土块、钩爪等视觉元素双格式音效兼顾主流浏览器兼容脚本承担了运行时与数据配置逻辑。项目结构清晰代码分层清楚离线部署非常方便能快速集成到个人网站、博客或游戏聚合站点也适合在此基础上扩展新玩法或调整难度。目前已有 547 人浏览学习对希望拥有一个可演示、可二次开发的 H5 小游戏项目的开发者来说是一套即拿即用的实战源码既能学习实现细节也能直接部署到自己的页面中。1. 为什么用 HTML5 重写《黄金矿工》一个可复用的网页游戏源码分析Flash 停售后很多当年打开浏览器就能玩的《黄金矿工》镜像站集体失效而这份源码包给出了一条更直接的替代路径它是用 HTML CSS JavaScript 编写的完整 HTML5 版本核心运行时由 Construct 2 导出所有逻辑都打包在index.html、c2runtime.js和data.js里不需要后端不需要安装插件双击index.html就能跑起来。对个人站长来说这是往自己网站里塞一个“摸鱼页”的高性价比方案对前端开发者和游戏爱好者来说这个包把爪子摆动、钩索回收、碰撞检测、关卡计时这几块最典型的小游戏逻辑完整暴露出来了可以直接拆开看内部实现。原作者还提供了在线演示地址可以在浏览器里先体验再决定要不要部署。2. Construct 2 运行时与项目文件结构c2runtime.js、data.js 和音频资源的分工拿到压缩包后第一眼看到的就是那一串.js和.m4a文件。这些文件不是随机堆在一起的它们的分工非常明确c2runtime.js是 Construct 2 导出的运行时引擎负责处理 Canvas 绘制、消息循环和对象实例管理data.js是整个游戏的项目数据文件包含所有布局、每个矿块的位置、对象类型和事件表逻辑jquery-2.1.1.min.js是运行时内部用来操作 DOM 和做 UI 事件绑定的辅助库offlineClient.js则是为离线缓存场景准备的客户端脚本。音频文件按用途命名game_music.m4a是背景音乐game_won.m4a、game_over.m4a、level_completed.m4a分别对应通关、失败和完成关卡时的提示音explosion.m4a则是抓爆石头的音效。2.1 项目文件骨架从 index.html 到 runtime 的加载顺序先打开index.html它的核心职责是按顺序加载上述脚本并在页面加载完成后启动 Runtime。一个标准的 Construct 2 导出页面结构大致如下!DOCTYPE html html langzh-cn head meta charsetutf-8 title黄金矿工/title script srcjquery-2.1.1.min.js/script script srcc2runtime.js/script script srcdata.js/script script srcofflineClient.js/script /head body canvas idc2canvas width960 height540/canvas script // 等待 DOM 就绪后把运行时绑定到指定的 canvas 上 $(function () { if (window.cr_createRuntime) { cr_createRuntime(c2canvas); } }); /script /body /html这里每个脚本的加载顺序是有讲究的jquery必须先加载因为c2runtime.js内部会依赖$data.js在c2runtime.js之后加载因为运行时解析项目数据时需要先定义好构造函数。最后的cr_createRuntime(c2canvas)接收一个 canvas 元素的 id参数对应页面里idc2canvas的标签换成别的名字运行时就会找不到画布。如果你想把游戏嵌进一个已经存在的网站只需要保留这段初始化逻辑再给 canvas 设置合适的宽高就能把游戏塞进页面里。2.2 data.js 里藏着什么游戏对象、布局与事件表序列化格式data.js是这份源码里最值得研究的文件。它的本质是一个大的 JavaScript 赋值语句把整个项目的数据序列化后挂到全局变量上c2runtime.js在启动时会读取这些数据来构建场景。结构上通常包含这样几个关键块数据块作用典型字段plugins所有插件类型列表name,id,parameterslayouts布局关卡场景定义name,width,height,objectsobjects某个布局中的所有实例x,y,width,angle,typeIdevents事件表游戏逻辑conditions,actions,triggersresources引用的图片和音频文件清单file,name我一般会用 VSCode 打开data.js先折叠代码搜索smallGold或diamond这类关键词就能定位到矿块对象定义的位置。虽然文件可能压缩成一行但字段名是可读的。比如一个典型的矿块实例定义可能长这样{ name: Rock, typeId: 5, width: 60, height: 60, instanceVars: { value: 200, hardness: 1 } }这里的instanceVars是对象实例变量value决定抓到后加多少分hardness决定抓取时需要多长的减速时间。修改这两个值就可以直接调整游戏经济平衡而不需要动任何逻辑代码。需要注意的是typeId是数字索引它对应了plugins数组里的某个插件类型改错数字游戏会崩溃所以只改instanceVars是更安全的。2.3 音频资源命名规范game_music、game_won、level_completed 等触发时机音频文件都是.m4a格式这是 Construct 2 默认的音频压缩格式在支持 H.264 的浏览器上兼容性最好。命名规则直接对应游戏状态game_music.m4a在进入游戏的主界面就开始循环播放level_completed.m4a在当前关卡的收集目标达成后播放然后进入下一关game_won.m4a在全部关卡打通后播放game_over.m4a在抓取失败或者时间耗尽、金币不足时播放explosion.m4a是钩爪碰到石头并引爆时的短音效。这些音效的引用事实上也写在了data.js的resources段里。如果你把其中的.m4a文件替换成同样文件名的新音频注意保持编码格式为 AAC 的.m4a浏览器才能正常解码。在下一章我会再聊更进阶的替换思路。3. 黄金矿工核心机制拆解爪子的角度摆动、碰撞检测与回收状态机黄金矿工看起来简单但真正的技术难点集中在三个地方爪子怎么摆、碰到矿块怎么判定、抓到后怎么收回来。这三步串起来就是一个连续的状态机缺少任何一环游戏手感都会崩掉。3.1 爪子摆动的数学实现正弦波与角度限制未出发时爪子会从一个锚点出发以固定周期在左右两个极限角度之间来回扫。常见的实现方法是使用正弦函数控制角度// 左方 60 度到右方 60 度周期 2 秒 let clawAngle 0; let swingTime 0; function updateSwing(dt) { // 每帧累加时间 swingTime dt; // 角度范围-60° 到 60°用 sin 保证平滑往返 clawAngle Math.sin(swingTime * 2 * Math.PI / 2) * 60 * Math.PI / 180; // 换算成统一角度单位后续用于计算钩爪方向 clawDirectionX Math.cos(clawAngle); clawDirectionY Math.sin(clawAngle); }参数60 * Math.PI / 180是把 60 度转换成弧度Math.sin产生 -1 到 1 的连续变化再乘以极限角度就得到了摆动的特征。周期由2 * Math.PI / 2决定其中分母2表示完成一个来回需要 2 秒。如果想让爪子摆动得更快、更难瞄准就把这个 2 改成 1.5想让新手更容易上手就改成 3。实际项目里不一定要用正弦也可以用Math.cos或者锯齿波但正弦的加速减速特性最接近原版手感。3.2 碰撞检测与抓取判定用矩形与圆形的几何测试钩爪头是一个直径很小的圆点矿块在 Canvas 上通常被简化为矩形碰撞体。从爪子当前坐标出发沿锁定角度方向每帧移动一段距离然后检测这个点是否与某个矿块矩形相交。常用做法是用“圆与矩形相交”测试function checkHit(px, py, rx, ry, rw, rh) { // 找出矩形中离圆心最近的点 const closestX Math.max(rx, Math.min(px, rx rw)); const closestY Math.max(ry, Math.min(py, ry rh)); // 计算该点到圆心的距离平方 const dx px - closestX; const dy py - closestY; // 半径默认为 8 像素距离小于半径即为碰撞 return (dx * dx dy * dy) 8 * 8; }这里的px、py是钩爪坐标rx, ry, rw, rh是矿块的左上角坐标和宽高。钩爪半径设成 8 是因为视觉上钩子头约 16 像素宽太大容易误抓太小会觉得判定过于严苛。每次移动钩爪后要对所有矿块循环做这个检测一旦返回true就说明抓住了矿块需要立刻记录该矿块对象并进入回收阶段。3.3 钩索回收与控制逻辑点击鼠标后的状态机转换整个爪子系统可以拆成三个状态SWING摆动、EXTEND伸出、RETRACT回收。点击屏幕是触发状态切换的闸门可以用一个简单的枚举值管理const ClawState { SWING: 0, EXTEND: 1, RETRACT: 2 }; let state ClawState.SWING; let clawX 480, clawY 80; // 锚点位置 let targetAngle 0; function handleClick() { if (state ClawState.SWING) { // 锁定当前摆动角度作为发射方向 targetAngle clawAngle; state ClawState.EXTEND; } } function updateClaw(dt) { const speed 300; // 每秒 300 像素 if (state ClawState.EXTEND) { clawX Math.cos(targetAngle) * speed * dt; clawY Math.sin(targetAngle) * speed * dt; // 超出画布边界则强制回收 if (clawX 0 || clawX 960 || clawY 540) { state ClawState.RETRACT; } } else if (state ClawState.RETRACT) { const homeX 480, homeY 80; const dirX homeX - clawX; const dirY homeY - clawY; const dist Math.sqrt(dirX * dirX dirY * dirY); if (dist 10) { clawX homeX; clawY homeY; state ClawState.SWING; } else { // 按当前距离方向移动并附带一点吸附效果 clawX (dirX / dist) * speed * dt; clawY (dirY / dist) * speed * dt; } } }这里targetAngle在点击时锁定保证伸出过程中爪子不会继续摆动。伸出速度为 300 像素/秒回收速度同样用 300但实际很多版本回收比伸出快 1.2 倍让玩家在抓到矿后不用等太久。状态切换的核心是handleClick里对state的判断它可以避免玩家在钩子伸出去时再次点击改变方向。如果游戏想要增加“点击后立即收回”的快捷操作就可以在state ClawState.EXTEND时也允许切换到RETRACT这是高级玩家会喜欢的一种微调。4. 参数在哪里改通过 data.js 调整矿块数量、价值和关卡节奏游戏能跑起来之后最常做的事情不是读逻辑而是改平衡参数。表面上你需要打开data.js去搜索但data.js内容很长直接搜索很容易眼花所以要先掌握它的结构再有针对性地改。4.1 矿块种类与价值表哪些字段控制分数和抓取难度在常规黄金矿工设计中矿块根据价值和抓取难度被划分为多个等级。我根据常见配置整理了一张属性对照表你可以在data.js的实例变量列表里找到对应参数矿块类型常见价值范围分硬度和抓取时间实例变量字段小金块20~50低0.3 秒value: 30, hardness: 0.3大金块100~300中0.8 秒value: 200, hardness: 0.8钻石400~800中高1.0 秒value: 600, hardness: 1.0石头0~5高1.5 秒value: 1, hardness: 1.5修改方式很简单在data.js里搜索value找到与矿块对象对应的那一层instanceVars块直接改数字。例如把石头改成价值 5会让它不再完全浪费玩家时间但抓取时间还是很长实际收益依然低。这种方法不需要懂 Construct 2 的事件语法只要保持 JSON 结构合法改动就安全。4.2 关卡时间与目标分数内置参数在哪定位除了单个矿块的价值整个关卡的目标分数、金币掉落数量也是游戏节奏的关键。这类全局参数通常存储在variables字段里例如variables: { TargetScore: 1500, LevelTime: 60, DrawSpeed: 360, MinGoldNeeded: 500 }LevelTime的单位是秒表示本关卡时长TargetScore是通关需要的分数MinGoldNeeded表示至少收集多少金币才能过关。把LevelTime从 60 改成 90玩家会明显感到前期压力变小适合用在个人网站的休闲页。DrawSpeed是钩爪伸出的速度改成420会让游戏节奏更快但注意不要设置超过 500否则一帧的移动距离过大会直接穿越细小的矿块产生穿模问题。4.3 从源码包到在线演示部署到个人网站的两种方式源码包里都是静态文件部署非常灵活。最简单的方式是本地跑一个 HTTP 服务因为直接双击index.html在部分浏览器里会因为 file 协议导致音频或资源加载失败。我习惯用 Python 自带的模块# 在项目根目录下执行 python3 -m http.server 8080然后浏览器访问http://localhost:8080。这个命令把当前目录映射成网站根目录-p 8080指定端口如果不写就默认 8000。如果想要正式放到云服务器上用 Nginx 更稳配置如下server { listen 80; server_name example.com; root /var/www/goldminer; index index.html; location / { try_files $uri $uri/ 404; } }这里的root指向你上传源码包的解压目录try_files是为了让浏览器可以正确找到index.html和后续的静态资源。部署完后记得检查c2runtime.js是否与data.js在同一目录下如果把data.js单独放到子目录运行时加载路径就会出错。另外在线演示环境里如果出现白屏大概率是音频文件路径大小写不一致Linux 服务器对大小写敏感建议保持全部小写文件名。5. 从模仿到改造利用现有源码扩展新矿种和替换音效的实战技巧到这个阶段游戏已经能跑、参数已经能调了但如果想让页面更有辨识度还需要做一些内容层面的替换。这套源码的扩展点其实很集中从调试到资源替换有一条清晰的路径。5.1 用 Chrome DevTools 直接观察运行时实例打开游戏页面后按 F12在 Console 里输入window.cr_getRuntime()可以拿到运行时对象然后展开它的allInstances属性就能看到当前场景里所有对象实例的实时状态。这里是判断矿块实例变量是否生效最快的方法。如果改了data.js后没生效先强制刷新缓存再在 Console 里检查对应对象的instance_vars属性比一遍遍重启游戏高效得多。5.2 替换音频文件的避坑指南要替换音乐最容易走弯路的是格式问题。.m4a文件在网页上的兼容性依赖浏览器的 H.264/AAC 支持如果你拿到的替换文件是.mp3可以先用 ffmpeg 转换# 将 mp3 转成 m4a保持原文件名覆盖原文件 ffmpeg -i new_music.mp3 -c:a aac -b:a 128k game_music.m4a参数-c:a aac指定音频编码为 AAC-b:a 128k设置码率这样转出来的文件不会因为体积太大拖慢首屏加载。替换后如果游戏没有声音打开 DevTools 的 Network 面板看game_music.m4a是否返回 404。如果返回 404十有八九是路径或文件名对不上。5.3 不打开编辑器也能新增矿种复制参数法在没有 Construct 2 编辑器的情况下给游戏加一种新矿块最安全的办法是复制现有对象定义。在data.js里找到一个简单的石头的实例变量定义复制一份然后修改它的name和instanceVars.value。比如把石头改成“神秘金矿”价值调成 300再修改它的animFrames或图片路径来改变外观。但注意typeId不能随意改复制对象后要使用一个新的typeId否则会被运行时当成原来的石头。具体操作就是在objects数组的末尾追加一个对象并把typeId设为当前最大索引加一同时确保同名的插件类型在plugins里已经存在。这个技巧的核心是让运行时能识别到一个新实例而不是非要对事件表做修改足够应付大多数自定义需求。本文还有配套的精品资源点击获取