首页  |  学习总览  |  ← 返回专题总览 进阶专题 15 · Unity WebGL

Unity WebGL 开发实战 🔥 游戏/3D

从 Unity 开发到 WebGL 导出,从性能优化到前端集成,掌握 Unity Web 开发全流程
学习时长:约 20 小时 | 前置:C# 基础、Unity 基础 | 产出:Unity WebGL 项目

一、Unity WebGL 概述

什么是 Unity WebGL?

Unity WebGL 是 Unity 平台的 Web 发布目标,通过 WebAssembly 和 WebGL 在浏览器中运行 Unity 内容。

Unity 编辑器
IL2CPP/WASM
WebGL 渲染
浏览器运行
特性说明
跨平台支持所有现代浏览器
高性能WebAssembly 接近原生性能
3D 能力完整 Unity 3D 功能
交互支持键盘、鼠标、触摸、游戏手柄
音频Web Audio API 集成

二、Unity 项目设置

2.1 构建配置

Player Settings

2.2 构建设置

// Unity 菜单:File → Build Settings → WebGL
// 关键设置:
// 1. Compression Format: Brotli
// 2. Name: webgl
// 3. Enable Exceptions: None
// 4. Data Caching: Enabled
// 5. Debugging: Disabled (发布时)

三、WebGL 前端集成

3.1 基础加载

// index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Unity WebGL</title>
  <script src="Build/UnityLoader.js"></script>
</head>
<body>
  <div id="gameContainer" style="width: 960px; height: 600px; margin: auto"></div>
  <script>
    var gameInstance = UnityLoader.instantiate(
      "gameContainer",
      "Build/webgl.json",
      { onProgress: unityProgress }
    );
    
    function unityProgress(gameInstance, progress) {
      if (!gameInstance.Module) return;
      const loader = document.querySelector("#loader");
      if (progress === 1) loader.style.display = "none";
    }
  </script>
</body>
</html>

3.2 新版 Unity (2020+) 加载

// 新版 Unity 使用 createUnityInstance
var buildUrl = "Build";
var loaderUrl = buildUrl + "/webgl.loader.js";
var config = {
  dataUrl: buildUrl + "/webgl.data.br",
  frameworkUrl: buildUrl + "/webgl.framework.js.br",
  codeUrl: buildUrl + "/webgl.wasm.br",
  streamingAssetsUrl: "StreamingAssets",
  companyName: "YourCompany",
  productName: "YourGame",
  productVersion: "1.0"
};

var container = document.querySelector("#unity-container");
var canvas = document.querySelector("#unity-canvas");
var loadingBar = document.querySelector("#unity-loading-bar");
var progressBarFull = document.querySelector("#unity-progress-bar-full");
var fullscreenButton = document.querySelector("#unity-fullscreen-button";

// 加载
createUnityInstance(canvas, config, (progress) => {
  progressBarFull.style.width = 100 * progress + "%";
}).then((unityInstance) => {
  loadingBar.style.display = "none";
  fullscreenButton.onclick = () => unityInstance.SetFullscreen(1);
}).catch((message) => alert(message));

四、Unity 与 JavaScript 通信

4.1 Unity → JavaScript

// Unity C# 代码
using UnityEngine;
using System.Runtime.InteropServices;

public class JSBridge : MonoBehaviour {
  [DllImport("__Internal")]
  private static extern void SendMessageToJS(string msg);

  public void OnGameOver(int score) {
    SendMessageToJSON(JsonUtility.ToJson(new GameResult { score = score }));
  }
}

// JavaScript 接收
function SendMessageToJSON(json) {
  const data = JSON.parse(json);
  console.log('游戏结束,得分:' + data.score);
}

4.2 JavaScript → Unity

// JavaScript 调用 Unity
function SendToUnity(methodName, param) {
  if (typeof param === 'object') {
    param = JSON.stringify(param);
  }
  gameInstance.SendMessage('GameManager', methodName, param);
}

// 调用示例
SendToUnity('SetLevel', '3');
SendToUnity('SetConfig', { volume: 0.8, quality: 'high' });

// Unity C# 接收
public void SetLevel(string level) {
  SceneManager.LoadScene("Level" + level);
}

public void SetConfig(string json) {
  var config = JsonUtility.FromJson<GameConfig>(json);
  AudioListener.volume = config.volume;
}

五、性能优化

优化策略

策略说明
压缩Brotli 压缩,体积减少 60-80%
资源优化纹理压缩、模型减面、音频压缩
代码裁剪Strip Engine Code,移除未使用模块
AssetBundle按需加载,减少首包体积
LOD多层次细节,远距离用低模
遮挡剔除不渲染被遮挡的物体
对象池复用对象,减少 GC

5.1 资源优化

// 纹理设置
// Max Size: 1024 或 512
// Compression: ASTC 或 ETC2
// Generate Mip Maps: 开启

// 模型设置
// Mesh Compression: Medium
// Optimize Mesh: 开启
// Generate Colliders: 关闭(除非需要)

六、React/Vue 集成

6.1 React 集成

// UnityCanvas.jsx
import { useEffect, useRef } from 'react';
import UnityLoader from 'react-unity-webgl';

export default function UnityCanvas() {
  const unityContext = new UnityLoader({
    loaderUrl: "Build/webgl.loader.js",
    dataUrl: "Build/webgl.data.br",
    frameworkUrl: "Build/webgl.framework.js.br",
    codeUrl: "Build/webgl.wasm.br"
  });

  useEffect(() => {
    unityContext.on("ready", () => {
      // Unity 加载完成
    });
  }, []);

  return (
    <UnityContextProvider unityContext={unityContext}>
      <canvas ref={canvasRef} />
    </UnityContextProvider>
  );
}

七、部署与运维

部署配置

// Nginx 配置
server {
    listen 80;
    server_name game.example.com;
    root /var/www/unity-webgl;

    // 开启 gzip
    gzip on;
    gzip_types application/javascript application/wasm application/octet-stream;

    // 缓存
    location ~* \.(wasm|data|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    // 跨域
    add_header Cross-Origin-Opener-Policy same-origin;
    add_header Cross-Origin-Embedder-Policy require-corp;
}

八、面试高频问题

Q1:Unity WebGL 和 Three.js 如何选择?
查看答案 ▼
维度Unity WebGLThree.js
学习成本高(需学 Unity + C#)低(纯 JS)
3D 能力完整(物理、动画、AI)基础(需自己实现)
性能WebAssembly,接近原生WebGL,依赖 JS
体积大(几 MB 到几十 MB)小(几百 KB)
适用场景游戏、复杂 3D展示、简单 3D
Q2:Unity WebGL 首屏加载慢怎么优化?
查看答案 ▼
  • 使用 Brotli 压缩
  • 启用 Data Caching
  • 使用 AssetBundle 按需加载
  • 减少首场景资源
  • 显示加载进度条
  • 使用 Loading 场景预加载