Unity | 优化专项-包体 | 字体

发布于:2024-04-28 ⋅ 阅读:(39) ⋅ 点赞:(0)

1. 字体包体占用

常用汉字字体文件大小通常在 10M~12M 左右,大概包含常见汉字 3.5w 个。我国汉字有大约将近十万个,全字库的大小对于游戏包体是灾难性的

在小游戏中,即使是常见汉字,大小也足以影响小游戏总包体,进而影响到下载及加载速度,因此在对游戏做包体优化时,字体也显得尤为重要

2. 字体子集化

所谓字体子集化,就是只提取需要用到的若干字形,生成一个非常小的字体文件,达到按需使用字形的效果

1. Fontmin

精简字体的工具有很多,这里推荐下 Fontmin,使用方法也很简单「http://ecomfe.github.io/fontmin/#terminal」

2. 提取项目中指定目录下的汉字

项目中可能用到汉字的文件主要包括配置文件(.json,.csv)、脚本(.cs)、场景(.unity)、预制体(.prefab)等,除了正式资源外,项目中也会存在测试资源,所以可以提取指定目录下的汉字

场景及预制体用文本编辑器打开后的格式:

在项目中编写插件,遍历上述文件,提取文件中的汉字,然后利用 Fontmin 生成字体文件

插件代码比较多,这里不再占用篇幅,需要的小伙伴可以在公众号回复:汉字提取

2. 常用 3500 字、7000 字

除了项目中必要的汉字外,如果允许用户自定义昵称,甚至聊天等,丢失的字符依然会影响视觉效果

作为常用汉字的基础补充,可以将常用 3500 字、7000 字也放入生成的字体文件中

3500 字的字体大小为1.1M,7000 字的字体文件大小为 2.2M,可根据需求自行评估选择

3. 构建时清除动态数据

随着编辑器的运行调试,字体资源的图集纹理也会越来越大,如果构建时不清除图集纹理,最终的包体中,图集纹理也会占用对应的空间

点击根据字体文件创建的 SDF 文件,在检视面板中勾选:Clear Dynamic Data on Build

勾选该选项后,编辑器在构建时,会清除字体资源的图集纹理,该纹理也将大小调整回大小为零

面板中其他参数,也可以根据需求自行调整

3. Fallback Font Assets

即使添加了常用 7000 字,也必然无法满足所有的汉字需求,所幸 TextMesh Pro 提供了 Fallback Font Assets 功能

官方对该功能的定义:字体图集(以及扩展的字体资源)只能包含一定数量的字形。确切的数字取决于字体、图集纹理的大小以及生成图集时使用的设置。当 TextMesh Pro 无法在文本对象的字体资源中找到字形时,后备字体系统允许您指定要搜索的其他字体资源

在 Android、iOS、微信小游戏(抖音小游戏暂不支持)平台,可以获取系统字体,动态创建备用字体资源,这样可以补充所有的字形,缺点是有可能和游戏中字体不一致,视觉效果差一些,但总要有取舍,就像这人生一样~

具体代码如下,备用字体可以换成所需的字体名字

#if UNITY_EDITOR
        return;
#endif

        void CreateFontAsset(Font font)
        {
            TMP_FontAsset fontAsset =
                TMP_FontAsset.CreateFontAsset(font, 32, 8, GlyphRenderMode.SDFAA, 1024, 1024);
            fontAsset.atlasPopulationMode = AtlasPopulationMode.Dynamic;
            fontAsset.isMultiAtlasTexturesEnabled = true;
            TMP_Settings.fallbackFontAssets.Add(fontAsset);
        }

#if WX
        WeChatWASM.WXBase.GetWXFont("", (font) =>
        {
            if (font != null)
            {
                CreateFontAsset(font);
            }
        });
#else
        string familyName = "";
#if UNITY_ANDROID
        familyName = Font.GetPathsToOSFonts()
            .FirstOrDefault(s => s.IndexOf("NotoSansCJK", StringComparison.OrdinalIgnoreCase) >= 0);
#elif UNITY_IOS
        familyName =
            Font.GetPathsToOSFonts().FirstOrDefault(s => s.IndexOf("PingFang", StringComparison.OrdinalIgnoreCase) >= 0);
#endif
        Font font = new Font(familyName);
        CreateFontAsset(font);
#endif
```

网站公告

今日签到

点亮在社区的每一天
去签到