2025-01-06 Unity 使用 Tip2 —— Windows、Android、WebGL 打包记录

文章目录

  • [1 Windows](#1 Windows)
  • [2 Android](#2 Android)
    • [2.1 横版 / 竖版游戏](#2.1 横版 / 竖版游戏)
    • [2.2 API 最低版本](#2.2 API 最低版本)
    • [2.3 目标帧率](#2.3 目标帧率)
      • [2.3.1 targetFrameRate](#2.3.1 targetFrameRate)
      • [2.3.2 vSyncCount](#2.3.2 vSyncCount)
      • [2.3.3 Unity 默认设置以及推荐设置](#2.3.3 Unity 默认设置以及推荐设置)
      • [2.3.4 Unity 帧率托管](#2.3.4 Unity 帧率托管)
  • [3 WebGL](#3 WebGL)
    • [3.1 平台限制](#3.1 平台限制)
    • [3.2 打包报错记录 1](#3.2 打包报错记录 1)
    • [3.3 打包报错记录 2](#3.3 打包报错记录 2)

​ 最近尝试将写的小游戏打包,主要平台包括 Windows、Android 和 WebGL,以下是一些打包过程记录。

  • Unity 版本:6000.0.26f1c1

1 Windows

​ 不得不说,Windows 平台是真好,打包一切顺利,没有任何卡壳,太感动了〒▽〒。

​ 点击 Build And Run,直接无脑生成 exe。

​ 小游戏的话不需要全屏,所以我设置了 Windowed。

2 Android

​ 需要做一些处理,没有那么顺利。

2.1 横版 / 竖版游戏

​ 需要设置游戏是横版还是竖版,我将 Default Orientation 设置了 Auto Rotation,即自动翻转,并将 Allowed Orientations for Auto Rotation 仅设置 Landscape Right/Landscape Left,即可以横版左右翻转。

​ 以下是相关设置说明:

  • Default Orientation:指定应用程序窗口在设备屏幕内的方向。

    可选项包括:

    1. Portrait:竖屏显示。
    2. Portrait Upside Down:竖屏倒立显示。
    3. Landscape Right:横屏显示(手机右侧朝下)。
    4. Landscape Left:横屏显示(手机左侧向下)。
    5. Auto Rotation:自动旋转。
  • Auto Rotation Behavior:自动旋转方式。

    可选项包括:

    1. User:用户可以锁定设备的自动旋转方向设置以关闭自动旋转。
    2. Sensor:依据设备传感器数据进行旋转,用户无法进行干预。

2.2 API 最低版本

​ Minimum API Level 必须手动设置,一般设置为 API Level 33,或者依据 Build 提示设为其指定值。我这里依据 Build 提示,设置为 API Level 34。

​ 有意思的是,Unity 默认会选很古老的 API,例如 Android 8.0(API Level 26)。

​ 但奇怪的是,在 Unity Hub 下载 Android 模块时,往往只下载了 API Level 33 ~ 35,这就非常搞鬼了,不手动设置的话,基本第一次 Build 都会报错,因为压根没装那么低版本的 API。

2.3 目标帧率

​ 通过 targetFrameRate(软件计时、手动设置)和 vSyncCount(硬件支持、自动设置)两种方式进行控制,只会同时生效其中一种(不考虑 VR 设备):

  • vSyncCount = 0 时,targetFrameRate 生效。
  • vSyncCount != 0 时,vSyncCount 生效。

2.3.1 targetFrameRate

targetFrameRate 是指定 Unity 尝试渲染游戏的目标帧速率,需要在程序运行之初使用代码进行设置。参考官方文档:https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Application-targetFrameRate.html

​ 不做任何手动设置时,Android 固定 30 fps 渲染(即 targetFrameRate = 30),以节省电池电量,与显示器的本机刷新率无关。

说明:

  1. targetFrameRate 只是帧率上限,实际帧率只会比这个值低或等于。

    不是说设置为 120 fps 后,老年机也能跑 120 帧。

  2. targetFrameRate = -1,表示帧率不封顶,帧数能跑多高就会跑多高。

  3. 受到显示器最大刷新率的限制,实际帧率不会超过显示器的本机刷新率。

    如果 targetFrameRate = 120,但是手机屏幕最高仅支持 90 帧,那么实际帧率最大也只能是 90。

  4. 在 Android 和 iOS 上,targetFrameRate 将向下舍入到能够整除显示器当前刷新率的最大值。

    例如,在 60Hz Android 显示器上运行时,且设置 targetFrameRate = 25 ,则设备帧率最高为 20fps,因为 20 是小于 25 且可以整除 60 的最高数字。

  5. 在 Windows 和 Web 上,不建议使用 targetFrameRate ,因为 targetFrameRate 基于软件计时,容易出现轻微卡顿现象。

​ 最初不知道如何设置的时候,导出 APK 在手机上运行时只有 30 帧超级卡,我还以为是自己性能优化没做好 hh。

2.3.2 vSyncCount

vSyncCount 表示每帧之间应传递的垂直同步数,即游戏允许在帧之间传递的屏幕刷新次数。范围是 0~ 4 内的整数,默认为 1。参考官方文档:https://docs.unity3d.com/6000.0/Documentation/ScriptReference/QualitySettings-vSyncCount.html

​ 假设目标设备显示器的刷新率为 90 fps,当 vSyncCount > 0 时,游戏目标帧为 90 / vSyncCount

vSyncCount 能够在 "Project Settings" -> "Quality"-> "VSync Count" 中进行设置:

  • Don't Sync:即 vSyncCount = 0
  • Every V Blank:即 vSyncCount = 1
  • Every Second V Blank:即 vSyncCount = 2

说明:

  1. 在 Android 和 iOS 上,vSyncCount 始终被忽略,因为移动设备不允许不同步渲染(使用 targetFrameRate 控制帧速率)。
  2. 在 Windows 和 Web 上,建议使用 vSyncCount,因为其基于硬件同步机制,能够产生完全无卡顿的输出。

2.3.3 Unity 默认设置以及推荐设置

平台 Unity 默认设置 推荐设置
Windows vSyncCount = 0, targetFrameRate = -1 (帧率不封顶,不同步渲染) 默认即可
Android / IOS targetFrameRate = 30 (固定 30 帧渲染) targetFrameRate = 60
WebGL vSyncCount = 1 (垂直同步,以本机显示刷新率渲染) 默认即可

​ 实现代码:

csharp 复制代码
public class GameStart : MonoBehaviour
{
    private void Awake()
    {
#if PLATFORM_ANDROID
        QualitySettings.vSyncCount  = 0;
        Application.targetFrameRate = 60;
#endif
    }
}

2.3.4 Unity 帧率托管

​ 在 "Project Settings" -> "Player"-> "Resolution and Presentation" -> "Resolution" 中,可勾选 "Optimized Frame Pacing",从而让 Unity 均匀分布帧,以减少帧速率的差异并创造更流畅的体验,提供更平滑的帧率表现。

​ 但参考该文:https://blog.csdn.net/m0_63261863/article/details/143192236,勾选可能导致游戏降频,建议结合自己情况勾选。

3 WebGL

​ WebGL 平台限制是真多,导出过程真的快吐了。

​ 但优点是链接点开即玩,所以没有办法。

3.1 平台限制

  1. 不支持访问本地文件。

    对资产数据和 AssetBundle 的网络请求会缓存在浏览器缓存中。

  2. 不支持多线程。

    不支持 C# System.Threading 命名空间中的任何内容。

  3. 不支持System.Net命名空间内的 .NET 网络类。

  4. 不支持 Unity 内部 AudioSource 与 AudioClip 的部分 API。

    这将导致,在 Unity 编辑器中使用 Addressables 模拟真机 AB 包加载音频时,无法正确播放。只能使用 Use Asset Database,或者将音频文件放在 Resources 文件夹下(不建议这样做)。

  1. 不允许使用 System.Reflection.Emit 动态生成代码。

  2. 不支持同步加载资源,只能异步加载。

3.2 打包报错记录 1

​ 一次偶然的机会,看到 Low 选项,不自觉设置为了 Medium。

​ 于是 WebGL 下打包报错,获取不到单例的非公共构造函数。

​ 报错代码:FrameworkException: Non-Public Constructor() not found! in Framework.Toolkits.PoolKit.SingletonObjectPool`1[Framework.Toolkits.AudioKit.AudioPlayer] at Framework.Toolkits.SingletonKit.SingletonCreator.CreateNonPublicConstructorObject[T] () [0x00000] in <00000000000000000000000000000000>:0

​ 查原因后,发现 Strip Engine Code 等级为 Medium 及以上时,会对反射的代码产生影响。而恰好,我的单例是通过反射获取私有无参构造函数创建的(官方链接:https://docs.unity3d.com/6000.0/Documentation/Manual/class-PlayerSettingsWebGL.html)。解决方案就是将 Strip Engine Code 等级调回 Low 即可。

  • Strip Engine Code:仅适用于 IL2CPP 脚本后端。

    勾选会剔除应用程序不使用的 DLL,以减少内置播放器的大小,建议勾选。

  • Managed Stripping Level:控制剔除程度。

    1. Minimal

      使用此选项以剥离类库、UnityEngine、Windows 运行时程序集,并复制所有其他程序集。

    2. Low

      删除无法访问的托管代码,减少构建大小和 Mono/IL2CPP 构建时间。

    3. Medium

      运行 UnityLinker 以减少代码大小,剔除范围大于 Low 选项,且某些反射代码路径的行为可能不同(支持自定义 link.xml 文件)。

    4. High

      运行 UnityLinker 进一步减少代码大小,剔除范围大于 Mediumm 选项,某些反射代码路径的行为可能不同,同时某些方法的托管代码调试可能不再起作用(支持自定义 link.xml 文件)。

3.3 打包报错记录 2

​ 有次无意间不满意新写的代码,直接将老版本代码(unitypackage)覆盖导入 Unity,之后再进行 WebGL 打包时发生如下报错:

复制代码
Build completed with a result of 'Failed' in 129 seconds (129224 ms)
Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output:

P:\Unity Project\Mine\Survivor Game 2.0>set MYDIR=S:\Unity Editor\6000.0.26f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\ 

P:\Unity Project\Mine\Survivor Game 2.0>goto FOUND_MYDIR 
wasm-ld: warning: function signature mismatch: UxmlFactory__ctor_m87E7DA1E842A9B4B4A45132392EDA2868D62B8A2
>>> defined as () -> void in P:/Unity Project/Mine/Survivor Game 2.0/Library/Bee/artifacts/WebGL/il2cppOutput/build/GameAssembly.a(3yoe1qmioyer.o)
>>> defined as (i32, i32) -> void in lto.tmp

wasm-ld: warning: function signature mismatch: VisualChangesProcessor_get_elementBuilder_m759F6B67F45FB60E9B1E4C646F26689258317B1E
>>> defined as () -> void in P:/Unity Project/Mine/Survivor Game 2.0/Library/Bee/artifacts/WebGL/il2cppOutput/build/GameAssembly.a(lsyvkdbleliz.o)
>>> defined as (i32, i32) -> i32 in lto.tmp

wasm-ld: warning: function signature mismatch: Area__ctor_m6128DC659857264FD4FBF06C01E0C2F04EAA4105
>>> defined as () -> void in P:/Unity Project/Mine/Survivor Game 2.0/Library/Bee/artifacts/WebGL/il2cppOutput/build/GameAssembly.a(kkef0xumaj1j.o)
>>> defined as (i32, i32, i32) -> void in lto.tmp

wasm-ld: warning: function signature mismatch: SingleQueryMatcher_IsInUse_mF17B2C22806E732E50055D4F6AC8A0E3ABEB4B99
>>> defined as () -> void in P:/Unity Project/Mine/Survivor Game 2.0/Library/Bee/artifacts/WebGL/il2cppOutput/build/GameAssembly.a(z4arkogp7up0.o)
>>> defined as (i32, i32) -> i32 in lto.tmp

...

​ 最初认为是项目中部分插件不支持 WebGL 平台,倒腾一番后,又重装了 WebGL 打包模块,依然是同样的报错。

​ 解决方案:删除该项目下的 Library 文件夹,Unity 重新打开项目,没有报错。

​ 分析原因:Library 中缓存的以前打包的结果,导致代码链接失败。

相关推荐
后端码匠2 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
敲代码的 蜡笔小新2 小时前
【行为型之中介者模式】游戏开发实战——Unity复杂系统协调与通信架构的核心秘诀
unity·设计模式·c#·中介者模式
tyn1882 小时前
记录一次conda虚拟环境pip安装报错[WinError 32] 另一个程序正在使用此文件,进程无法访问
windows·conda·pip·虚拟环境·虚环境
梓仁沐白3 小时前
Android清单文件
android
敲代码的 蜡笔小新5 小时前
【行为型之解释器模式】游戏开发实战——Unity动态公式解析与脚本系统的架构奥秘
unity·设计模式·游戏引擎·解释器模式
董可伦6 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空6 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭6 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin
Magnum Lehar7 小时前
3d游戏引擎的Utilities模块实现
c++·算法·游戏引擎
flying robot8 小时前
小结:Android系统架构
android·系统架构