Unity 小游戏试玩打包中的字体包体问题

一、问题背景

我在尝试使用团结引擎制作小游戏试玩广告时,发现最终发布出来的渠道 ZIP 包接近 25MB。

但这个项目本身只是一个纯 UI 小游戏,内容非常简单:

  • 单场景
  • 少量 UI 图片
  • 没有模型、复杂特效或大型音频

按理说,这样的项目不应该有这么大的包体。后来排查资源时,我发现项目使用了一个完整的中文 TMP 字体:

MSYH SDF

这个字体资产是由微软雅黑生成的。将它替换或移除后,包体明显下降,因此可以确定:完整中文字体是这次包体过大的主要原因之一。


二、为什么一个字体会占这么大体积

TextMeshPro 字体并不只是一个简单的配置文件,它通常包含或引用:

原始字体文件
+ TMP Font Asset
+ SDF Atlas 字形图集
+ 字体材质
+ Fallback 后备字体

其中真正容易占用大量空间的是:

  • .ttf.otf 等原始字体文件
  • SDF 字形图集
  • 动态生成的多张 Atlas
  • Fallback 引用的其他完整字体

中文字体包含数千甚至数万个汉字,原始字体文件本身就可能达到数 MB甚至十几 MB。

如果 TMP 字体使用的是 Dynamic 模式,为了能够在运行时生成任意字符,通常还需要把完整的原始字体文件打进构建包。


三、Static 和 Dynamic 字体的区别

Dynamic 字体

Dynamic 字体可以在运行时生成新的字形,适合:

  • 玩家昵称
  • 聊天内容
  • 用户输入
  • 无法提前确定的文本

但它也可能带来:

  • 完整中文字体进入构建包
  • 运行时生成字形产生开销
  • Atlas 满后继续生成新图集
  • 包体和内存难以控制

Static 字体

Static 字体只包含提前生成的字符,适合:

  • 固定 UI 文本
  • 小游戏
  • WebGL
  • Playable Ads

它的优点是包体可控,不需要携带完整字体。缺点是没有提前加入的字符会显示为方框。

因此可以遵循:

固定文本使用 Static
不可预测文本才使用 Dynamic

四、Atlas 为什么也会占空间

TMP 会把生成后的字符保存在 Atlas Texture 中。

常见尺寸包括:

512 × 512
1024 × 1024
2048 × 2048
4096 × 4096

Atlas 越大:

  • 能容纳的字符越多
  • 构建包体越大
  • 运行时显存占用越高
  • 加载时间越长

如果开启 Multi Atlas Textures,当前 Atlas 放不下新字符时,还会继续生成多张图集。

对于文字数量固定的小游戏试玩,没有必要使用大型动态 Atlas 或多图集。


五、Fallback 字体也可能被打进包体

Fallback Font Asset 用于主字体缺字时查找后备字体。

需要检查:

TMP Font Asset
→ Fallback Font Asset Table

以及:

Project Settings
→ TextMeshPro
→ Fallback Font Assets

即使场景没有直接使用完整中文字体,只要它被设置成 Fallback,也可能因为资源引用被打进构建包。

所以替换字体后,还需要清理字体资产和 TMP Settings 中的后备字体引用。


六、小游戏和 Playable 应该怎么处理字体

小游戏试玩通常具有以下特点:

  • 文本数量较少
  • 文本内容固定
  • 不需要玩家自由输入
  • 对包体和首次加载速度要求严格

因此,我应该为试玩项目单独生成一套静态字体:

专用 Static TMP Font Asset
+ 只包含实际使用的字符
+ 使用 512 或 1024 Atlas
+ 关闭 Multi Atlas
+ 移除完整中文 Fallback
+ 不携带完整源字体

例如试玩中只会出现这几个字符:

运营一个月
当前资金
收入
成本
下一回合
游戏失败
立即挑战
程序员
电脑
服务器
0123456789
+-×%!?

那么字体资产只需要包含这些字符,不需要把完整的微软雅黑字库打进项目。


七、以后如何避免这个问题

原型阶段

原型阶段可以暂时使用 Dynamic 字体,优先保证开发效率和避免缺字。

但要明确:

Dynamic 中文字体只是临时方案,不应该直接作为小游戏或 Playable 的最终发布字体。

内容确定后

我需要收集项目中实际使用的全部字符,包括:

  • 场景中的 TMP 文本
  • Prefab 中的文本
  • 代码动态拼接的文字
  • 数字与标点
  • 结算提示
  • 结束页 CTA

然后使用这些字符生成专用的 Static Font Asset。

发布前检查

Font Asset 是否为 Dynamic
是否携带完整 .ttf 或 .otf
Atlas 分辨率是否过大
是否开启 Multi Atlas
是否存在完整中文 Fallback
TMP Settings 是否引用大型字体
字体是否放在 Resources 中
构建报告中字体占用了多少空间

修改完成后重新构建,并对比优化前后的 ZIP 大小。


八、结论

这次问题让我意识到:

纯 UI 项目并不代表包体一定很小,完整中文字体甚至可能比全部 UI 图片和游戏代码加起来还大。