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

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
```
<think>嗯,用户之前问过关于在C#中遍历字典时的注意事项,现在又转向了UGUI优化的问题。看来他们可能在开发Unity游戏,遇到了性能方面的问题,尤其是在UI部分。需要先理解UGUI优化的常见痛点和解决方法。 首先,UGUI的优化通常涉及渲染、布局、Draw Call等方面。用户可能在游戏中遇到UI卡顿或者帧率下降的问题,尤其是在移动设备上。需要从几个方面入手:比如减少Canvas的重绘,合理使用图集,避免不必要的Raycast Target,以及优化布局组件等。 用户之前的问题是关于字典遍历的,可能现在他们在处理UI时遇到了性能瓶颈,比如滚动列表卡顿,或者UI元素过多导致渲染压力大。需要分步骤解释优化策略,确保结构清晰,符合他们之前接受的回答风格。 要注意用户可能对UGUI的基础有一定了解,但需要具体的优化技巧。可能需要涵盖静态和动态Canvas的分离,图集的使用,顶点数的控制,以及避免在运行时频繁修改UI元素的位置或大小等。另外,可能还需要提到使用对象池来处理大量UI元素,比如滚动列表中的项。 还要考虑到用户可能在移动平台上开发,所以需要强调性能敏感的方面,比如Overdraw的控制,禁用不必要的Raycast,以及使用Profiler工具来检测性能瓶颈。同时,可以补充一些常见的误区,比如误用Mask组件导致额外的Draw Call,或者频繁调用SetActive导致的性能问题。 需要确保回答结构清晰,分点说明,每个部分有具体的例子和代码片段,比如如何分离Canvas,如何使用图集,如何优化文本组件等。此外,可能还需要比较不同方法的优缺点,帮助用户根据具体情况选择最合适的优化策略。 最后,总结部分要简明扼要,方便用户快速回顾重点。可能还需要提到一些工具的使用,比如Unity的Frame Debugger和Profiler,帮助用户自行诊断问题。确保回答内容准确,覆盖主要的优化方向,同时避免过于技术化的术语,保持易懂。</think>以下是针对 **Unity UGUI 优化**的详细指南,涵盖常见性能瓶颈、优化技巧及解决方案: --- ### 一、UGUI 性能核心问题 1. **Draw Call 过多** - **原因**:每个不同材质/纹理的 UI 元素会触发独立的 Draw Call。 - **优化目标**:通过合并 Draw Call 减少 GPU 负载。 2. **Canvas 频繁重建(Rebuild)** - **原因**:UI 元素的位置、尺寸、材质等变化时,Canvas 会触发重建(`Canvas.SendWillRenderCanvases`)。 - **优化目标**:减少动态 UI 元素的布局计算频率。 3. **顶点数超标** - **原因**:复杂图形(如高精度图片、文字)产生过多顶点。 - **优化目标**:控制单个 UI 元素的顶点数量。 --- ### 二、关键优化策略 #### **1. Canvas 分层管理** - **静态与动态分离** 将频繁变化的 UI(如血条、计时器)与静态 UI(如背景)分配到不同 Canvas: ```csharp // 示例:创建两个 Canvas public Canvas staticCanvas; // 设置为不触发重建 public Canvas dynamicCanvas; // 允许动态更新 ``` > **原理**:修改子 Canvas 时,仅该 Canvas 触发重建,避免全局刷新。 - **层级嵌套优化** 避免多层嵌套 `Canvas` 或 `Canvas Group`,嵌套会强制合并所有子元素的 Draw Call。 --- #### **2. 图集(Atlas)与合批** - **使用 Sprite Atlas** 将多个 UI 图片打包为图集,确保相同材质的元素合并 Draw Call: ```csharp // Unity Editor 中创建 Sprite Atlas // 路径:Window > 2D > Sprite Atlas ``` > **注意事项**: > - 图集尺寸不超过目标平台限制(如移动端建议 2048x2048)。 > - 避免透明区域过大的图片(浪费合批空间)。 - **禁用不必要的 `Raycast Target`** 无交互需求的 UI 元素(如纯图片)关闭射线检测: ```csharp Image img = GetComponent<Image>(); img.raycastTarget = false; // 减少 EventSystem 的计算开销 ``` --- #### **3. 文本(Text)优化** - **优先使用 `TextMeshPro`** TextMeshPro(TMP)比原生 `Text` 组件性能更优,支持更精细的字体控制。 - **字体设置技巧**: - 使用 `Character Set` 最小化字体文件(仅包含必要字符)。 - 启用 `Font Asset` 的 `Atlas Population Mode` 为 `Dynamic`,动态加载缺失字符。 - **避免频繁更新文本内容** 缓存需要动态更新的文本,减少 `SetText()` 调用频率: ```csharp private int cachedScore; public TMP_Text scoreText; void UpdateScore(int newScore) { if (cachedScore != newScore) { scoreText.SetText(newScore.ToString()); cachedScore = newScore; } } ``` --- #### **4. 滚动列表(ScrollView)优化** - **使用对象池(Object Pooling)** 对大量列表项(如背包、排行榜)复用已创建的 UI 元素: ```csharp public class ScrollViewPool : MonoBehaviour { public GameObject itemPrefab; private Queue<GameObject> pool = new Queue<GameObject>(); public GameObject GetItem() { if (pool.Count > 0) return pool.Dequeue(); return Instantiate(itemPrefab); } public void ReturnItem(GameObject item) { item.SetActive(false); pool.Enqueue(item); } } ``` - **禁用 `Mask` 的 `Reverse Mask`** `Reverse Mask` 会生成额外的 Draw Call,非必要时应关闭。 --- #### **5. 动画与特效控制** - **避免使用 UI 组件的 `Animator`** UI 动画优先使用 `DoTween` 或 `LeanTween`,比 Unity Animator 更轻量。 - **粒子特效分离** 将特效渲染到独立的 `Render Texture` 或使用 `CanvasRenderer` 外的粒子系统。 --- ### 三、性能检测工具 | 工具 | 用途 | |----------------------|----------------------------------------------------------------------| | **Frame Debugger** | 分析 Draw Call 合批情况,定位合批失败原因 | | **Profiler > UI** | 监控 Canvas 重建耗时、Batch 数量、顶点数等关键指标 | | **Unity UI Profiler**| 第三方插件,提供更详细的 UI 性能分析(如布局计算耗时) | --- ### 四、常见误区与解决方案 | 误区 | 解决方案 | |-------------------------------------|--------------------------------------------------------------------------| | **频繁调用 `SetActive()`** | 使用 `CanvasGroup.alpha` 控制显隐,或通过位移移出屏幕 | | **过度使用 `Layout Group`** | 静态布局预计算坐标,动态布局限制刷新频率(如每 5 帧更新一次) | | **忽略 `Overdraw`** | 简化 UI 层级,避免半透明元素叠加 | | **未压缩纹理** | 使用 ASTC/ETC2 压缩格式,减少纹理内存占用 | --- ### 五、移动端专项优化 1. **控制帧率** 对非游戏场景(如设置界面)限制帧率以节省电量: ```csharp Application.targetFrameRate = 30; ``` 2. **禁用 `Multi-touch`** 若无需多点触控,关闭冗余输入检测: ```csharp Input.multiTouchEnabled = false; ``` 3. **GPU Instancing** 对重复 UI 元素(如图标)启用 GPU Instancing(需材质支持)。 --- ### 总结:UGUI 优化优先级 1. **合并 Draw Call**(图集、材质共享) 2. **减少 Canvas 重建**(动静分离、避免频繁布局) 3. **控制顶点数量**(简化图形、压缩文本) 4. **优化滚动列表**(对象池、禁用 Mask) 5. **工具辅助分析**(Frame Debugger、Profiler) 通过上述策略,可显著提升 UGUI 性能,尤其在低端设备上效果更为明显。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值