跳转到内容

平台要求

GameTok 支持各种流行的游戏开发环境。开发者可以使用 Unity、Cocos Creator 或 HTML5 等工具,并遵循特定的导出配置以确保兼容性。

Unity WebGL 输出设置

  1. 打开 Unity 项目并确保所有必要的资源都已导入。
  2. 前往 File > Build Settings,选择 WebGL 作为目标平台,然后点击 Switch Platform。
  3. 调整 Player Settings(分辨率、压缩)以优化性能。
  4. 点击 Build 生成包含 HTML、JavaScript 和 WebGL 数据文件的 WebGL 输出文件夹。

注意:这些文件是部署在 GameTok 上所必需的。

请如下图所示配置新项目:

注意:WebGL 文件夹将包含部署在 GameTok 上所需的 HTML、JavaScript 和 WebGL 文件。

游戏开发完成后,请使用以下配置进行导出:

GameTok 发布了一款 Unity 插件,以帮助 Unity 开发者优化纹理和资源包,并更好地与 GameTok 平台集成。

下载 Unity 插件:Lobah AssetOptimizationTool v0.1.5

Unity 插件:Asset Optimization Tool

插件导入说明:打开 Windows -> PackageManager,点击左上角的“+”图标,选择“Add Package from disk”,浏览到此插件的根目录,并选择 package.json 文件。要使用该插件,请点击菜单栏中的“AssetOptimization”按钮。

纹理压缩工具

纹理压缩工具是一个可视化的纹理资源分类和管理工具。该工具旨在方便项目中的纹理管理。它允许用户查看纹理的内存使用情况、压缩格式、尺寸和其他信息。它还支持批量修改纹理的压缩格式、最大尺寸和 mipMap 设置。 首先,在 Project 面板中选择任意目录,然后点击 BrowseAllTexturesInDirectory 按钮。如果目录中包含纹理,将显示目录中所有纹理的列表,如下图所示:

注意:如果在未选择任何目录的情况下点击 BrowseAllTexturesInDirectory 按钮,它将列出项目中的所有纹理。如果项目中有大量纹理,此步骤可能需要一些时间。

列表左侧显示列表中纹理的总体信息,包括所选纹理的数量、纹理总数以及纹理的总内存使用情况。列表还支持排序以方便用户搜索,可以按默认顺序(即文件夹顺序)、内存使用情况、压缩格式或 mipMap 进行排序。

列表分为八列,分别显示纹理名称、压缩格式、内存使用情况、最大尺寸、宽度、高度、纹理类型以及是否启用了 mipMap。对于资源优化,最重要的三条信息是内存使用情况、压缩格式和最大尺寸。纹理的压缩格式和最大尺寸决定了其内存使用情况。

当您在列表中选择任何项目时,左侧会出现三个新按钮:Change Format、Change Max Texture Size 和 Enable MipMap。它们的功能分别是更改压缩格式、更改最大尺寸以及启用或禁用 mipMap。列表支持使用 Shift 或 Ctrl 键进行多选以进行批量操作,如下图所示:

该插件支持选择各种常用的纹理压缩格式。对于 WebGL 移动平台,通常建议使用 ASTC。ASTC 是一种先进的压缩格式,支持多种不同的压缩比,从而在质量和文件大小之间取得良好平衡。该插件还支持修改纹理的最大尺寸,范围从 4096 到 32。由于 WebGL 平台最高仅支持 2048x2048,因此建议使用 1024x1024 或 512x512 的纹理以实现兼容性和性能,这可以提高加载速度并减少内存使用(对于某些纹理,根据实际项目情况可以使用 256x256 或更小)。该插件还支持一键启用或禁用纹理的 mipMap。MipMap 是一种纹理优化技术,主要用于图形渲染中的纹理映射。它提供同一纹理的多个分辨率版本,以提高渲染性能和视觉质量。启用 mipMap 后,Unity 会在渲染过程中根据对象与摄像机的距离选择最合适的 mipMap 级别。如果对象远离摄像机,则会自动使用较低分辨率的 mipMap,从而减少 GPU 计算和内存带宽使用,进而提高渲染性能。但是,我们仅建议对具有高分辨率和丰富细节且需要在近处和远处都保持视觉质量的纹理启用此选项。


AssetBundle Manager

AssetBundle Manager 是一款可视化的打包工具,支持资源包的创建、管理、打包、预览等实用功能,帮助用户更方便地管理打包过程。 该工具的主菜单位于顶部,分为三个类别:Configuration、Generation 和 Inspection,对应三个页面。

Configuration 页面

当没有配置任何资源包时,此页面将提示用户从 Project 面板拖动资源以生成资源包,或通过右键单击鼠标创建新的资源包。拖动资源生成资源包的原理与将资源标记为 AssetBundle 或 Addressable 相同。资源可以是预制件、纹理、材质、模型、场景等。这里,我们以预制件“rocks”为例,并将其拖到 Config 面板中。

此时,Config 面板分为四个模块。左上角是 AssetBundles 列表。在此列表中选择任何资源包时,左下角将显示所选资源包的详细信息和依赖信息。右上角列出了所选资源包中包含的资源(例如,一个预制件可能包括材质、纹理、模型、音频等多种资源)。在右上角列表中选择任何对象时,右下角将显示所选对象的属性,如下图所示:

新建资源包:在左上角空白区域右键单击以添加新的空包或文件夹,以创建您的自定义资源包。您可以将 Project 面板中的任何资源拖到自定义包中,或者在选择资源包时,将右上角列表中的一个或多个资源拖到自定义包中。在资源移动过程中,插件会自动查找资源的所有依赖项并将它们打包在一起。

查看资源详情:右侧列表有四列,分别是资源名称、所属资源包、大小和提示信息。如果某行为灰色且其资源包为“auto”,则表示此资源是依赖项,并自动打包到资源包中。例如,材质中包含的所有纹理资源都是依赖项。如果将此材质添加到资源包 A,则其包含的所有纹理资源将自动打包到 A 中并以灰色显示。

重复资源的检测和修复:该工具会自动检测依赖资源是否在多个资源中重复。仍然以材质为例,可能存在多个材质共享一个纹理的情况。如果将这些材质放置到不同的资源包中,同一个纹理将被多次打包,导致不必要的内存浪费。接下来,我们通过将岩石中的一个材质拖到新创建的资源包“test”中进行测试,您会发现右侧列表中的某些资源被标记为黄色警告,如下图所示:

这些黄色警告标记了重复的资源。您可以选择移除或将这些资源移动到新的包中。在左上角任何资源包上右键单击,然后选择“Move duplicates to new bundle”,以自动将该包的重复资源移动到新包中。右键菜单还包括以下常用功能:Add Sibling、Convert to Variant、Rename Package、Delete Package。

如果包中有任何错误的资源,右侧列表中将出现一个错误图标。将鼠标悬停在上面将显示错误详细信息。

Build 页面

在此页面上,您可以选择目标构建平台(默认为 WebGL)和输出路径(默认为 AssetBundles/)。用户有两个可选设置:

  • 清空文件夹内容并重新生成
  • 复制到 StreamingAssets 文件夹以便在测试期间方便加载

🚀 AB 包的本地加载测试 点击 Build 按钮开始生成 AssetBundle 文件。检查生成的文件夹,您会发现除了 AB 包文件外,还有相应的 manifest 文件。这些文件是加载所需的配置文件。例如,要从 StreamingAssets 文件夹加载 AssetBundles,核心代码如下:

c#
 private void Start()
 {
     GameObject rock = LoadAsset<GameObject>("rocks", "rocks");
     Instantiate(rock);
 }

 public T LoadAsset<T>(string abName, string assetName) where T : Object
 {
     AssetBundle ab = null;
     string abResPath = Path.Combine(Application.streamingAssetsPath, abName);
     ab = AssetBundle.LoadFromFile(abResPath);

     T t = ab.LoadAsset<T>(assetName);
     return t;
 }

将此脚本附加到场景中的任何对象上,点击 Play,您将在编辑器中看到加载的预制件:

如果要通过网络加载在线 AB 包,只需使用以下方法(填写 AB 包的 URL):

c#
 private IEnumerator LoadAssetBundleFromURL(string url, string abName)
  {
      using (UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url))
      {
          yield return www.SendWebRequest();

          if (www.result != UnityWebRequest.Result.Success)
          {
              Debug.LogError($"Error loading AssetBundle: {www.error}");
              yield break;
          }

          AssetBundle ab = DownloadHandlerAssetBundle.GetContent(www);
          GameObject asset = ab.LoadAsset<GameObject>(abName);
          Instantiate(asset);
      }
  }

加载依赖项测试 在上述加载测试中,我们只加载了 AssetBundle 文件(没有扩展名的文件),而没有加载其依赖文件(即同名但扩展名为 .manifest 的文件)。如前所述,在实际项目中,我们可能会遇到多个预制件共享公共部分的情况,因此我们可以将公共部分打包成一个单独的 AssetBundle。其他不同部分则会对这个公共部分产生依赖。加载时,我们也必须加载依赖项;否则,将发生资源丢失,预制件将无法按预期显示。 首先,添加一个新方法来生成 AssetBundleManifest,以便后续进行依赖查找:

c#
 private AssetBundleManifest m_manifest;
 public void Init()
 {
     string streamingAssetsAbPath = Path.Combine(Application.streamingAssetsPath, "WebGL");
     AssetBundle streamingAssetsAb = AssetBundle.LoadFromFile(streamingAssetsAbPath);
     m_manifest = streamingAssetsAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
 }

该方法应在程序启动时调用。其目的是定位名为 WebGL 的文件(具体名称取决于您的构建平台;由插件自动生成)并加载它以生成 AssetBundleManifest。

接下来,增强 LoadAsset 方法以加载目标包的所有依赖项:

c#
public T LoadAsset<T>(string abName, string assetName) where T : Object
{
    AssetBundle ab = null;
    string abResPath = Path.Combine(Application.streamingAssetsPath, abName);
    ab = AssetBundle.LoadFromFile(abResPath);

    //New
    string[] dependences = m_manifest.GetAllDependencies(abName);
    int dependenceLen = dependences.Length;
    if (dependenceLen > 0)
    {
        for (int i = 0; i < dependenceLen; i++)
        {
            string dependenceAbName = dependences[i];
            Debug.Log("dependName:" + dependenceAbName);

            string _path = Path.Combine(Application.streamingAssetsPath, dependenceAbName);
            AssetBundle dependenceAb = AssetBundle.LoadFromFile(_path);
        }
    }

    T t = ab.LoadAsset<T>(assetName);
    return t;
}

该插件还提供了一些在打包过程中可能有用的一些高级设置:

  • Compression:选择不压缩、标准 LZMA 或基于块的 LZ4 压缩。
  • Exclude type information: 不在资源包中包含类型信息。
  • Force rebuild: 重新构建需要构建的包。这与“clear folder”不同,因为此选项不会删除不再存在的包。
  • Ignore type tree changes: 在增量构建检查期间忽略类型树更改。
  • Append hash: 在资源包名称后附加哈希值。
  • Strict mode: 如果在构建过程中报告任何错误,则不允许构建成功。
  • Dry run build: 执行空运行构建。

Inspector 页面

您通过 Build 页面构建的路径将自动添加到此处。此页面的功能如下:

  • 点击“Add File”或“Add Folder”以添加要检查的包。
  • 点击每行旁边的“-”以删除文件或文件夹。请注意,您无法删除通过文件夹添加的单个文件。
  • 选择任何列出的包以查看详细信息,包括: 1.名称 2.磁盘大小 3.源资源路径:明确添加到此包中的资源。请注意,此列表对于场景包是不完整的。 4.高级数据:包括预加载表、容器(显式资源)和依赖信息。

由于 iOS 对 Unity Web 游戏的支持存在一些限制,我们为 Unity 开发者设计了以下指南,以便快速将使用 Unity 开发的游戏集成到 GameTok 平台。

请尽量根据文档和调试信息优化您的 Unity WebGL 游戏。GameTok APP 会检查游戏。如果游戏与 IOS 不兼容,可能只会在 Android 版本上提供。

兼容性评估清单

功能是否支持解决方案
Unity 的基础模块支持支持动画、物理、AI、UI 等基础模块。
渲染管线支持支持标准渲染管线和URP
纯 TypeScript支持需要 iOS 14.5 或更高版本,支持 JIT
Unity 音频支持使用 UnityWebRequest 进行 HTTP 通信,使用 WebSocket 通信替代方案(如开源的 UnityWebSocket 插件)进行 TCP 通信。
网络系统需要调整使用 UnityWebRequest 进行 HTTP 通信,使用 WebSocket 通信替代方案(如开源的 UnityWebSocket 插件)进行 TCP 通信。
渲染接口支持仅支持 WebGL 1.0(相当于 OpenGLES 2.0)
多线程不支持移除多线程使用,改用异步方法等替代方案。

导出要求

Unity WebGL 输出设置

  1. 打开 Unity 项目并确保所有必要的资源都已导入
  2. 前往 File > Build Settings,选择 WebGL 作为目标平台,然后点击 Switch Platform
  3. 调整 Player Settings(分辨率、压缩)以优化性能
  4. 点击 Build 生成包含 HTML、JavaScript 和 WebGL 数据文件的 WebGL 输出文件夹

注意:WebGL 文件夹将包含部署在 GameTok 上所需的 HTML、JavaScript 和 WebGL 文件。

游戏开发完成后,请使用以下配置进行导出:

为更好的 WebGL 兼容性进行配置

  1. 启用 WebGL 2.0(如果需要,可回退到 WebGL 1.0) iOS Safari 支持 WebGL 2.0,但存在限制。 在 Unity 中,前往: Edit > Project Settings > Player > WebGL > Other Settings 启用 WebGL 2.0,但也要启用 WebGL 1.0 回退以获得更广泛的兼容性。
  2. 增加内存大小 iPhone 在使用 WebGL 时经常会耗尽内存。 在 Unity 中,设置更高的内存限制: Edit > Project Settings > Player > WebGL > Other Settings > Memory Size 将其增加到 256MB 或 512MB,但不要太高(iOS 可能会崩溃)。
  3. 更改纹理压缩格式 在 Project Settings → Player → WebGL → “Texture Compression Format” 中,选择 ETC2 或 ASTC。(Unity 2021+ 和 URP 强烈建议使用 ASTC 以获得更好的移动兼容性。)
  4. 检查/移除不兼容的着色器 如果“Hidden/VoxelizeShader”或“HDRDebugView”是 URP 调试着色器,请尝试前往 Graphics Settings → “Strip Unused Shader Variants”以减少无用的子着色器
  5. 优化移动端构建 禁用异常: Edit > Project Settings > Player > WebGL > Publishing Settings > Enable Exceptions > None 启用数据缓存: Edit > Project Settings > Player > WebGL > Publishing Settings > Data Caching 禁用调试模式以获得更好的性能。
  6. 修复 iOS 特定问题 iOS Safari 会阻止某些 Unity 功能: 禁用触摸输入延迟: Edit > Project Settings > Player > WebGL > Other Settings > Input Handling > Both 允许全屏模式: 某些游戏如果在全屏模式下启动会崩溃。在 Unity 设置中禁用全屏。
  7. 使用 WebGL 加载器优化进行测试 使用压缩纹理和 LZ4 压缩以减小构建体积。 在 WebGL 设置中使用 Fastest Graphics API。

常见原因与修复

A. iOS WebGL 可能内存不足

检查内存使用情况

  • 打开 iPhone Safari Web Inspector 。
  • 检查 JavaScript Heap Size 。
  • 如果超过 256MB ,iOS 可能会强制 WebGL 崩溃

🚀 修复

  • 进一步降低 纹理分辨率 (在可能的情况下使用 256x256 纹理 )
  • 降低网格复杂性 (如果使用高多边形模型)。
  • 在 Unity 中对纹理使用 Crunch Compression ( ASTC 4x4 或 ETC2 )。

B. IndexedDB 加载失败

检查您的游戏是否正在使用 IndexedDB(在 iOS Safari 上可能会失败)

  • 在 Safari 的 私密浏览模式 中,IndexedDB 通常被 阻止
  • 一些 Unity 构建会 自动使用 IndexedDB 进行缓存

🚀 修复

  • 前往 Unity WebGL Player SettingsPlayer → WebGL → Publishing Settings.
  • 将 "Data Caching" 设置为 Disabled.
  • 将此代码添加到您的 index.html中:
    javascript
    if (window.indexedDB) {
      console.log("IndexedDB is supported");
    } else {
      console.warn("IndexedDB is NOT supported - potential issue on iOS");
    }

C. iOS 在用户未交互前会阻止音频播放

检查音频是否播放失败

  • iOS 会阻止自动播放音频.
  • Unity WebGL 会尝试自动启动音频, 这可能会导致游戏崩溃

🚀 修复

  • 修改您的 index.html, 仅在用户交互后才启用音频:
    javascript
    document.addEventListener("touchstart", function () {
      if (typeof UnityAudio !== "undefined") {
        UnityAudio.resume();
      }
    });
  • 确保在 Unity 中 没有音频源会自动播放

D. WebGL 上下文可能丢失

检查 Safari 日志中是否出现 “WebGL context lost

  • 某些 iPhone 在切换标签页或内存峰值后无法恢复 WebGL 。

🚀 修复

  • 将此代码添加到您的 Unity WebGL 模板中:
    javascript
    canvas.addEventListener(
      "webglcontextlost",
      function (event) {
        event.preventDefault();
        alert("WebGL context lost, please reload the page.");
      },
      false
    );

E. JavaScript 错误

检查 JavaScript 代码是否崩溃

  • 在 Mac Safari 中打开 Web Inspector (DevelopiPhoneConsole).
  • 检查与 JavaScript 相关的错误

🚀 修复

  • 如果您看到 Uncaught TypeError, 请确保 Unity 正在正常加载:
    javascript
    window.onerror = function (message, source, lineno, colno, error) {
      console.error("Global Error:", message, "at", source, "line:", lineno);
    };

Swipe & Play Endless Game Together