Skip to Content
文档完整案例

完整案例

本章用于复现三个具体项目。标题为“仅本案例”的目录、命令、坐标和补丁只用于相应示例。源码附件用于继续开发,dist 附件用于运行或发布;示例源码不包含作者的账号凭证或 Post 绑定,发布自己的版本时先 create。

H5 · 星星冲刺

45 秒内收集 5 颗星星,避开 2 个巡逻机器人,初始 3 点生命。WASD / 方向键移动,P 暂停,R 重玩,手机视口提供屏幕方向键。完整源码含免构建版与 Vite 工程。

下载并在本地运行

操作位置: 新建的 native-h5 文件夹与终端。

操作: 下载本节源码附件,解压到 native-h5,让 package.json 直接位于该目录根部。终端进入这个目录后,在下面两条路线中选一条执行。

成功现象: 免构建版打开 8000,Vite 开发版打开 5173;均出现星星冲刺的开始界面。

python3 -m http.server 8000 --bind 127.0.0.1 --directory plain/dist
npm ci npm run dev

本机示例目录是桌面 Move to Combos/native-h5;解压到其他位置时使用自己的路径。浏览器打开免构建版 http://127.0.0.1:8000/ 或 Vite 开发版 http://127.0.0.1:5173/。

图 05|星星冲刺本地运行,先验证开始、移动和收集计分。

图 05|星星冲刺本地运行,先验证开始、移动和收集计分。

验证、构建和发布

操作位置: 本地浏览器、native-h5 根目录终端与 Combos 页面。

操作: 点击开始,移动到星星,检查分数增加;收齐 5 颗显示获胜。验证碰撞扣血、超时失败、P 暂停和 R 重玩。Vite 路线停止 dev 后执行 build 和 preview,打开 4173;免构建路线直接使用 plain/dist。完成后按发布与更新发布。

成功现象: 最终成品和线上版本都能运行核心玩法;保留自己的 combos.json 继续修改。

npm run build npm run preview

本次实际发布 Vite 生成的 dist,平台声明 pc,mobile,revision 1。打开星星冲刺 ;Canvas 搜索码 07752。本地与线上键盘完整通关;手机方向键仅完成浏览器视口检查,未计入手机真机验收。

图 06|星星冲刺从 Combos 公开页面运行并收集到第一颗星星。

图 06|星星冲刺从 Combos 公开页面运行并收集到第一颗星星。

源码说明和附件

文件负责的内容
index.html / src/style.cssCanvas、HUD、按钮、布局和手机方向键
src/main.js输入、移动、收集、碰撞、倒计时、胜负和绘图
package.json / vite.config.js开发、构建、预览和相对资源地址
plain/dist/同一玩法的直接 HTML + JS 成品,无需编译

下面说明案例如何计分,完整程序在源码附件中。它不是接入 Combos 的必需代码,也不是终端命令。

if (!star.collected && Math.hypot( star.x - state.player.x, star.y - state.player.y ) < 35) { star.collected = true; state.score++; } if (state.health <= 0 || state.elapsed >= 45) show('lost'); else if (state.score === 5) show('won');

源码: 包含两个制作版本和封面,适合跟做、修改。** 成品:** 两个 dist ZIP 都可解压后运行;根目录直接有 index.html。

star-sprint-source.zip

star-sprint-html-dist.zip

star-sprint-vite-dist.zip

Unity 案例 · BoatAttack

使用 Unity 官方 BoatAttack,固定基线 91886a3ef1ac963aa10578fcaf1d59e9b6961ab3。原基线使用 6000.2.0b8,本例适配 Unity 6.3 LTS 6000.3.25f1(Apple Silicon ARM64)。保留原船只、驾驶员、Island 场景、水面、物理、AI 和 C# 玩法。

获取并适配这个示例

操作位置: 准备复现示例的空目录和终端。

操作: 安装 Git LFS,克隆官方项目并切换到固定基线;执行 lfs pull 获取大型资源。把本节适配包解压到工程根目录,检查并应用补丁,再由 Unity Hub 打开。

成功现象: 模型和贴图完整,工程能在示例指定编辑器中导入;补丁仅应用一次。

git clone https://github.com/Unity-Technologies/BoatAttack.git BoatAttack cd BoatAttack git checkout 91886a3ef1ac963aa10578fcaf1d59e9b6961ab3 git lfs pull git lfs fsck # 把本节适配包解压到这个全新工程根目录后: git apply --check tracked-project-changes.patch git apply tracked-project-changes.patch

已适配的本机工程不要再次应用补丁。自己的游戏直接使用Unity 原生导出的原生导出流程。本适配包包含版本和兼容性修改、说明与许可证,不含大型原资产、Library 或 dist,也不安装 Combos 插件。

原生导出并进入比赛

操作位置: Unity 编辑器、项目终端与浏览器。

操作: 打开 main_menu.unity,Play 检查菜单和单人比赛设置,再停止 Play。按Unity 原生导出原生构建:Scene List 为 main_menu.unity(0)和 level_Island.unity(1),Default 模板、Gzip + fallback、Addressables 随 Player 构建。输出到 dist。

成功现象: 原生 Build 成功,网页主菜单和 Island 比赛均可进入,动态船只与 UI 正常加载。

图 07|BoatAttack 原工程在 Unity 中显示主菜单。

图 07|BoatAttack 原工程在 Unity 中显示主菜单。

图 08|BoatAttack 单人比赛设置;选 Island 后进入船只配置。

图 08|BoatAttack 单人比赛设置;选 Island 后进入船只配置。

本次原生按钮 Build 于 18:21:57 开始、18:26:03 成功,耗时 246 秒。生成 27 个文件、5 个 Addressables bundle;成品 127.36 MiB,最大单文件 94.58 MiB,ZIP 124.88 MiB。整体和单文件符合当前限制,ZIP 根部直接有 index.html。

python3 -m http.server 8001 --bind 127.0.0.1 --directory dist

浏览器打开 http://127.0.0.1:8001/。操作顺序:RACE → SINGLEPLAYER → ISLAND(1 圈)→ NEXT → 船只配置 → RACE。等待开场和倒计时,点击画布取得键盘焦点;W / ↑ / 空格加速,A/D 转向,R 重置,F 暂停与继续。

上传和线上验证结果

首次发布自己的版本时,截取实际比赛画面保存 cover.png,按发布与更新创建。该示例使用 --platform pc --screen-orientation landscape;本机已绑定的同一游戏则使用 update。本次以原生成品更新至 revision 2,回执已发布且 submission_is_current=true。大包可按需增加 --timeout 10m。

打开 BoatAttack ;Canvas 搜索码 08759。停止本地服务后,在两个独立浏览器会话从公开试玩页和分享链接进入比赛,验证加速、转向、暂停与继续,并在其中一个会话验证 R 重置;试玩全程静音。核心文件和 5 个 bundle 从公开部署加载,未见游戏运行错误。

图 09|BoatAttack 原生 Default 成品在 Combos 线上进入比赛并驾驶。

图 09|BoatAttack 原生 Default 成品在 Combos 线上进入比赛并驾驶。

验证范围为 PC 横屏单人比赛加载和驾驶;完整比赛获胜、手机触控与手机真机未计入本次验收。加载器、引擎等仍有警告;外层页面未登录用户 profile 的 401 与游戏加载分开记录。

保留了什么,具体改了什么

内容本次处理
C#、船、人物、岛屿、物理、AI保留原代码和资产,由 Unity 导出;水面沿用原项目已有 WebGL 分支
网页入口与模板Unity 自带 Default 自动生成;没有改写 loader 或新增 Combos 网页模板
发布场景、压缩、Addressables在 Unity 原生界面保存导出配置
编辑器 / Input System / URP示例版本适配及编辑器序列化变化,见完整补丁
UIPanelFade.shader增加新版 uGUI 所需的 _MainTex 属性,修复示例菜单材质
此前自定义构建工具Editor 构建脚本、Combos 模板和 com.unity.pipeline 已移除
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}

适配补丁相对固定官方 commit 覆盖 31 个已跟踪文件,包含 README-migration.md、WEBGL-MIGRATION.md、LOCAL_SETUP.md 和许可证。补丁是这个开源项目的复现材料,不是所有 Unity 游戏的接入步骤。

boatattack-adaptation.zip

Roblox 案例 · Ball Game

原项目来源:Ball game open source ,以 ball game.rbxl 提供。本例保留 5 秒开场、推粉色球绕过三道错位砖墙、接触 WinPiece 后变金色并显示 Winner 的规则。

运行原版,记录人物与场景

操作位置: Roblox Studio。

操作: File → Open from File 打开原 .rbxl,Play / F5 试玩,再停止测试。Explorer 中读取两个 ServerScriptService 脚本 CreateBall 和 GetWinner,并查看 Workspace 中的 Map1、WinPiece、SpawnLocation、Baseplate。

成功现象: 原规则、人物原型与场景参数能对应到实际画面;原 .rbxl 保持不变。

图 10|Roblox 原版人物、草地、砖墙、灰色底板与终点。

图 10|Roblox 原版人物、草地、砖墙、灰色底板与终点。

图 11|原 GetWinner 源码监听球与 WinPiece 的接触。

图 11|原 GetWinner 源码监听球与 WinPiece 的接触。

两个脚本负责开局造球和获胜。渲染、人物、输入、镜头、动画、物理和服务端执行环境由 Roblox 提供。原球尺寸为 5×5×5 studs;草地为 18×1×74;三道障碍中心为 (22,17.5,34)、(32,17.5,15)、(21.5,17.5,-4)。这些数值仅属于 Ball Game。

Ball.Touched:Connect(function(partTouching) if partTouching.Name == "WinPiece" then Ball.BrickColor = BrickColor.new("Gold") warn("Winner!") game.Workspace.Map1.PlayerWon.Value = true end end)

需要检查自己的简单 Part 场景时,可停止 Play,在 Studio Command Bar 执行下面的只读命令,查看 Output。复杂 Mesh、贴图或骨骼另行处理;这段命令只打印属性,不会导出一个可运行的 H5 游戏。

for _, part in ipairs(workspace:GetDescendants()) do if part:IsA("BasePart") then print(part:GetFullName(), part.Position, part.Size, part.Material, part.Transparency) end end

对照新的源码和还原效果

Roblox 中的来源H5 源码本例如何处理
CreateBall:wait(5)、Part、Neonsrc/main.js保留 5 秒等待;球的可见网格与动态物理刚体一起创建
GetWinner:Touched、PlayerWonsrc/main.js接触终点后一次获胜、球变金色、显示 Winner
Map1、WinPiece、出生点等src/level.js + main.js读取尺寸与坐标重建网格和碰撞体,保留透明挡墙的物理作用
草地、砖墙、金属、泥地、天空src/environment.js用浏览器材质和本地纹理重建外观
R15 Man / Pal Hair / 摩托衫 / 牛仔裤src/avatar.js按原型重建 15 个身体分段、发束、笑脸、衣物与白底鞋
Humanoid 与默认第三人称镜头main.js + avatar.js + camera.js实现移动、跳跃、动作、跟随、拖动旋转与缩放
Message / Hint 等 UIindex.html + src/style.css改为浏览器 HUD、开局、暂停和获胜界面

人物由原版运行时加载账号 Avatar。本例按外形原型用本地几何和纹理重建,没有直接导入 Roblox 官方网格。场景以简单 Part 为主,按真实布局重建;其他项目可以复用有权导出的模型和贴图。

图 12|H5 人物正面保留发型、笑脸、蓝黑上衣、深色裤子和白底鞋。

图 12|H5 人物正面保留发型、笑脸、蓝黑上衣、深色裤子和白底鞋。

图 13|H5 人物侧面展示头发、身体分段和鞋的形体。

图 13|H5 人物侧面展示头发、身体分段和鞋的形体。

本例约定 1 stud = 0.3m,原点取 Roblox (27,15,15),球半径因此是 0.75m。这个坐标换算、质量、摩擦、滚动阻尼和速度限制均属于案例实现;自己的游戏按自己的数据和物理体验调整。

图 14|H5 完整关卡按原版数据恢复三道障碍、边界和终点位置。

图 14|H5 完整关卡按原版数据恢复三道障碍、边界和终点位置。

ballBody.addEventListener('collide', event => { if (event.body !== winPiece.body || state.mode !== 'playing' || state.won) return; state.won = true; state.phase = 'finished'; pink.color.set('#fff000'); pink.emissive.set('#fff000'); glow.material.color.set('#fff54b'); document.querySelector('#status').textContent = 'Winner!'; show('won'); });

新增的浏览器能力包括触屏方向键与跳跃、暂停与继续、重玩、全屏、人物近景查看,以及 WebGL 不可用提示。Roblox 账号、Robux、多人同步和云存档未迁移;本例不是 Roblox 运行时的完整兼容层。

下载完整源码并验证

操作位置: 新建的 ball-game-h5 文件夹、终端和浏览器。

操作: 下载本节源码附件,解压后让 package.json 位于根部,再进入该目录执行 npm ci 和 npm run dev。源码包含 level.js、avatar.js、environment.js、camera.js、main.js、SOURCE-MAPPING.md 及 reference/ 下原 Lua 副本。

成功现象: 浏览器打开 5174 后出现开始界面;开局等待 5 秒,再出现粉色球、原型人物、草地、三道墙和终点。

npm ci npm run dev

本机示例路径是桌面 Move to Combos/ball-game-h5。浏览器打开 http://127.0.0.1:5174/。WASD / 方向键移动,空格跳跃,拖动鼠标旋转镜头,滚轮缩放;P 暂停,R 重玩,F 全屏。“查看人物”冻结本局并展示近景,“返回游戏”继续。

图 15|Ball Game H5 本地第三人称视角,开始后实际推动粉色球。

图 15|Ball Game H5 本地第三人称视角,开始后实际推动粉色球。

默认视角下,推球依次从右、左、右绕过三道墙,再进入末端凹槽。球与 WinPiece 实际接触后变金色并出现 Winner。本地已通过真实键盘与物理推球完成通关,并检查跳跃落地、暂停、重玩、镜头和人物查看。

图 16|本地完整推球通关后,球变金色并显示 Winner。

图 16|本地完整推球通关后,球变金色并显示 Winner。

构建、发布和线上验证

操作位置: ball-game-h5 根目录终端与浏览器。

操作: 停止 dev,执行 build 和 preview,打开 4174 检查最终成品。源码附件已有 cover.png;按发布与更新先 create 自己的游戏,之后保留自己的 combos.json 使用 update。

成功现象: 最终 dist 的人物、场景、操作和获胜都可运行;停止本地服务后从自己的分享链接再次完成验证。

npm run build npm run preview

本次在原 Post 更新人物和场景至 revision 2,已发布,回执 submission_is_current=true。打开 Ball Game H5 ;Canvas 搜索码 70261。线上完成键盘推球通关;手机按钮仅完成浏览器视口检查,未计入手机真机验收。

图 17|关闭本地服务后,在 Combos 页面运行新版 Ball Game H5。

图 17|关闭本地服务后,在 Combos 页面运行新版 Ball Game H5。

源码: 完整 H5 工程、原版 Lua 参考和逐项源码映射,适合跟做和修改。** 成品:** 可解压运行的 dist ZIP,适合检查发布结构。

ball-game-source.zip

ball-game-dist.zip


来源:Combos 开发者接入指南 。原文核对日期:2026-10-08,CLI v1.14.2;案例结果为原文记录的实测结果。

Last updated on