Article

Unity WebGL 小游戏实战 01:构建管线与运行时约束(先把发布底座做对)

路线阶段:从 Unity 入门进入 Unity WebGL 小游戏开发。
本章目标:先把 WebGL 发布链路跑通且可维护,再谈玩法扩展。

学习目标

完成本章后,你应该能做到:

  1. 配置 Unity WebGL 构建参数并理解关键取舍。
  2. 建立构建后产物结构认知(loader/data/framework/wasm)。
  3. 规划内存预算与资源加载策略,避免浏览器崩溃。
  4. 打通本地调试、线上发布与回归验证流程。

WebGL 与原生平台的核心差异

  1. 单线程主循环为主,阻塞更敏感。
  2. 内存受浏览器环境限制,峰值容易触顶。
  3. 文件 IO 与网络策略不同(CORS/缓存/压缩)。
  4. 输入焦点、全屏、鼠标锁定受浏览器策略约束。

构建参数建议

Player Settings(WebGL)

  1. Compression Format:优先 Gzip(兼容)或 Brotli(体积更小)。
  2. Data Caching:开启,减少二次加载耗时。
  3. Exception Support:开发期 Explicitly Thrown,发布期降级。
  4. Memory Size:按项目规模设置(例如 256MB~512MB 起步)。
  5. Name Files As Hashes:开启,便于 CDN 缓存更新。

构建脚本化

using UnityEditor;

public static class WebGlBuildScript
{
    public static void BuildRelease()
    {
        var scenes = new[]
        {
            "Assets/Game/Scenes/Boot.unity",
            "Assets/Game/Scenes/Main.unity"
        };

        var options = new BuildPlayerOptions
        {
            scenes = scenes,
            locationPathName = "Build/WebGL",
            target = BuildTarget.WebGL,
            options = BuildOptions.None
        };

        PlayerSettings.WebGL.compressionFormat = WebGLCompressionFormat.Gzip;
        PlayerSettings.WebGL.nameFilesAsHashes = true;
        PlayerSettings.WebGL.dataCaching = true;

        var report = BuildPipeline.BuildPlayer(options);
        if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
        {
            throw new System.Exception("WebGL build failed");
        }
    }
}

构建产物认知

典型 WebGL 构建目录:

Build/WebGL/
  index.html
  Build/
    xxx.loader.js
    xxx.data
    xxx.framework.js
    xxx.wasm
  TemplateData/

职责:

  1. loader.js:初始化加载流程。
  2. data:资源数据包。
  3. framework.js:运行时桥接层。
  4. wasm:核心逻辑编译产物。

自定义加载模板

建议在 WebGLTemplates/U3DC/index.html 里加入:

  1. 加载进度条。
  2. 失败重试按钮。
  3. 版本号显示(构建时间 + git hash)。
  4. 移动端/桌面端提示与降级说明。

示例关键段:

<div id="loading">
  <div id="progress-bar"><span id="progress"></span></div>
  <button id="retry" style="display:none;">重试加载</button>
</div>
<script>
  function setProgress(v){ document.getElementById('progress').style.width = (v*100)+'%'; }
</script>

运行时内存预算

预算建议(首版)

  1. 逻辑与运行时:80~120MB
  2. 纹理与模型:80~200MB
  3. 音频缓冲:20~60MB
  4. 临时峰值预留:40~80MB

治理策略

  1. 降低大纹理分辨率,优先压缩格式。
  2. 音频分层加载(常驻 BGM + 按需 SFX)。
  3. 场景切换时触发 UnloadUnusedAssets
  4. 避免一次性加载所有关卡资源。

浏览器输入与焦点治理

重点处理:

  1. 首次点击后才允许音频播放。
  2. 失焦时自动暂停或降速。
  3. 鼠标锁定失败时降级 UI 提示。
private void OnApplicationFocus(bool focus)
{
    if (!focus)
    {
        Time.timeScale = 0f;
        EventBus.Publish("WebGlFocusLost", null);
    }
    else
    {
        Time.timeScale = 1f;
        EventBus.Publish("WebGlFocusBack", null);
    }
}

网络与缓存策略

  1. 服务器正确返回 Content-Encoding(gzip/br)。
  2. .data/.wasm 设置长期缓存 + hash 文件名。
  3. index.html 短缓存,确保版本切换生效。
  4. 跨域资源加载时配置 CORS。

调试与监控

至少接入:

  1. 启动耗时(首屏出现时间)。
  2. 资源加载失败率。
  3. 平均帧率与长帧占比。
  4. 内存峰值与异常退出记录。

与前面章节联动

  1. 资源加载系统:按 boot/battle_core/stage 分组加载。
  2. 输入抽象系统:适配浏览器焦点与触控。
  3. 流程状态机:增加 WebGLLoading 可视状态。
  4. 存档系统:准备浏览器存储适配层。

验收清单

  1. 本地与测试环境可稳定构建并运行 WebGL。
  2. 首次加载与二次加载时间符合预期。
  3. 失焦/恢复后输入与音频状态正确。
  4. 发布包可通过版本号定位具体构建。

常见坑

坑 1:构建参数手工点选

多人协作容易漂移。应脚本化并纳入版本控制。

坑 2:内存只看平时不看峰值

实战高峰会崩。必须压测大波次与高特效场景。

坑 3:缓存策略和文件命名冲突

旧包未刷新导致奇怪报错。hash 命名与缓存规则需配套。

本月作业

完成一版可发布 WebGL 基线包:

  1. 自定义加载页 + 进度与重试。
  2. 构建脚本一键产出发布包。
  3. 输出首包体积、加载耗时、内存峰值报告。

下一章进入 Unity WebGL 小游戏实战 02:首个可玩关卡(目标、失败条件、结算循环)。