# UI 图集自动化方案(AIGame) > 2026-10-22 移植 ClientTrunk 的 `SpriteAtalsGenerator`、`AssetBundleBuildRules.ProcessAtlas` 与 `GEngine.AtlasManager` 核心链路;适配本项目 Unity 2022.3、YooAsset 3.0.6、HybridCLR。 ## 1. 目标 - 美术/AI 把切图放入约定目录。 - 导入为 `Sprite (2D and UI)`,关闭 mipmap。 - Prefab / 运行时按 **Sprite 短名** 引用(与 JSON `assets.sprites` 一致)。 - 图片导入、删除、移动后延迟合并更新;每个实际含图片的目录生成一个 `.spriteatlas`,构建时原图与图集同包。 ## 2. 目录 ```text AIClient/Assets/Bundles/UI/Texture/ Common/ # 通用控件(对应 UI_*_Set) / # 业务专用 AIClient/Assets/Bundles/UI/Atlas/ UI_CommonAtlas.spriteatlas UI_HomeAtlas.spriteatlas UI_PrototypeAtlas.spriteatlas ``` 中间产物仍可先落在 `Tools/output/`,再导入 Bundles。 ## 3. 切图来源 1. 选图集级别:`UI_Simple_Set` / `UI_Normal_Set` / `UI_Pic_Set`。 2. `Tools/gpt_image_generate.py` 生成(>1K 用 `gpt-image-2-vip`,见 `ResourceCreate.md`)。 3. 风格:`Doc/Design/UI_Design_Principles.md` + `ui_design.jpg`。 4. 切片坐标以对应 `Doc/UI_*_Set.md` 为准;登记 `Doc/ResDesc_Picture.md`。 ## 4. 导入建议 - Texture Type:`Sprite (2D and UI)` - Sprite Mode:单图 `Single`;整图集再切为 `Multiple` - Mesh Type:`Full Rect`(九宫格) - 标准控件底图必须设置有效非零 Border,JSON 使用 `imageType: Sliced`;按钮各状态图同样设置。Common 的 26 张 Normal Set 控件由 `UiSpriteNineSliceRules.cs` 自动导入维护;新增控件时同步扩展规则。已有资源可执行 `Tools/UI/Apply Standard Control Nine-Slice` 后重建对应 Prefab。 - Alpha Is Transparency:开 - `UI/Texture/` 下原图由 `TexturePlatformPostprocessor` 保持 RGBA32、Compression=None,关闭 Crunch 和四个平台的原图覆盖;保留其他导入参数。平台压缩仅应用于最终 SpriteAtlas:Windows(Standalone)DXT5,iOS(iPhone)和 Android 为 ASTC 6×6,WebGL 为 ASTC 8×8,关闭 Crunch。目录外图片继续沿用平台压缩规则。 ## 5. 自动生成与构建 `Assets/Editor/UI/UiSpriteAtlasGenerator.cs` 扫描 `Texture/` 的 Texture2D,按直接父目录分组,支持 Single / Multiple Sprite。嵌套目录独立成图集,不会被父图集重复收集。目录分隔符编码为 `_s`,下划线编码为 `_u`,防止 `A/B` 与 `A_B` 同名。根目录直接放的图片归 `UI___RootAtlas`。`UiAtlasPaths` 为编辑器和运行时提供同一套路径规则。 图集采用 SpriteAtlas V1 `AlwaysOnAtlas`;最大页尺寸 2048,padding=4,不旋转、不紧密打包、不生成 mipmap,保留 Sprite Border。图过多时由 Unity 自动产生多页。必须开启 Include in Build(与参考工程一致),使当前 SBP 的 `PackAllAtlases` 建立打包关联,`StripUnusedSpriteSources` 才能剥离未压缩原图像素。图集与原图的 Sprite 对象仍由 YooAsset 同包分发,运行时加载器保留延迟绑定兼容。 已有图集原地更新,保留 GUID。无变化不重写;仅清理带 `AIGame.UI.GeneratedAtlas` 标签且已无源图的图集,不清空 Atlas 目录。生成前检查非 Sprite 输入、目录大小写冲突和同一图集中的重复 Sprite 名。普通导入回调只调整新导入图片的 Sprite / mipmap / alpha / NPOT 设置,不修改已有九宫格边界。 `Tools/UI/Generate Sprite Atlases` 可手动校验生成。`SetupUiBundleCollector.Setup` 在 Art 构建前执行生成并配置: | 收集内容 | 类型 | 规则 | | --- | --- | --- | | `UI/Prefab` | MainAssetCollector | 保留原 Prefab 名地址与独立包 | | `UI/Atlas` | MainAssetCollector | `CollectUiAtlas` + `PackUiAtlas` | | `UI/Texture` | DependAssetCollector | `CollectUiAtlasTexture` + `PackUiAtlas` | 图集用文件名寻址;原图不额外增加短名地址,通过依赖进入其图集同名 bundle,避免跨目录重名图片引起地址冲突。既有 Art 构建入口 `BuildAndStageArt` 已调用此 Setup,无需维护第二个构建入口。Prefab 无需重建或改用图集中的克隆 Sprite。 ## 6. 运行时 `UiManager.Init` 在打开 UI 前注册 `UiAtlasLoader`。Unity 发出 `SpriteAtlasManager.atlasRequested` 后,加载器从首选包、Art、DefaultPackage 中异步加载 `UI_` 前缀图集并回调绑定。打开 Prefab 时等待在途图集加载完成。请求合并,共用图集句柄和 Sprite 克隆;失败可重试;随 UI 根节点销毁注销事件、释放句柄及克隆。 动态换图示例(Coroutine): ```csharp yield return UiManager.Instance.Atlases.SetSpriteAsync(image, "Home", "home_ico_coin"); // 或仅加载 Sprite: yield return UiManager.Instance.Atlases.LoadSpriteAsync("Common", "btn_primary_normal", sprite => { /* 使用 */ }); ``` 目录字符串替代参考项目与具体业务耦合的 `AtlasEnum`。多个并发请求不会重复加载;同一个 Image 后发请求优先。Editor 可回退 AssetDatabase 以支持本地预览,Player 全部走 YooAsset 异步加载。 ## 7. 验证 `AIClient/AgentScripts/VerifyUiAtlases.cs` 通过 unity-pipeline 执行:`Editor` 校验平台参数、打包后 Sprite / Border、GUID 幂等与 Art 实际构建映射;`AutomaticChanges` 使用临时图片验证导入/移动/删除自动维护后清理;`BuildIsolated` 只向 `Tools/output/ui_atlas` 构建独立验证包,不替换 CDN / StreamingAssets;`PrepareRuntimeScene`/`Runtime`/`RestoreRuntimeScene` 在空场景实测真实资源包与禁用 Editor fallback 的异步加载,随后恢复原场景。回执同目录。 2026-10-22 验证通过:编辑器 394 项、自动增删移动 6 项、真实 WebGL 资源包的 Editor Play Mode 加载 12 项。3 个图集分别覆盖 Common 38/Home 16/Prototype 13 张图片;二次生成 updated=0,原 GUID 和九宫格边界保留。运行时验证包含 Prefab 自动绑定、并发 Sprite 缓存、Image 后发请求优先和销毁释放;没有使用 AssetDatabase fallback。`dialog.png` 为真实包内对话框的 540×960 离屏渲染,面板/按钮/关闭图标显示正常。最终恢复 Boot 场景,无未保存内容;未执行浏览器或微信真机验证。 同日原图压缩规则调整后,`ApplyUncompressedSources` 已迁移全部 67 张原图为未压缩 RGBA32,四个平台覆盖关闭,GUID 和 Border 保留;更新后的 Editor 796 项检查、自动增删移动 7 项检查均通过,最终三个图集的平台压缩规则保留。目录外图片另通过 13 项导入/重新导入检查,继续使用原平台压缩规则。原图迁移回执见 `Tools/output/ui_atlas/source_uncompressed.json`。 同日修复包体膨胀:旧的 `Include in Build=false` 导致 SBP 保留源图像素。真实 Art Home 包 `a6442d30c6c5d555575f90ae44067db5` 为 3,044,323 字节,并包含 16 个 RGBA32 Texture2D。恢复 `Include in Build=true` 后,隔离验证包为 271,138 字节,源 Texture2D 为 0,16 个 Sprite 保留;运行时真实 Home 页为 2048×1024、ASTC_8x8,实际包内 UI 渲染/动态换图/释放通过。Atlas 预览约 0.5 MiB 是纹理数据大小,bundle 经 LZ4 后可更小。`AuditUiAtlasBundle.cs` / `Tools/output/ui_atlas/size/` 提供前后对象检查与字节数,Runtime 检查已增加非空实际纹理断言。正式 Art 包须重新构建后采用本次修复。 随后完整 Art 构建还发现旧缓存问题:`20261022.142050` 的 Home 包 `ef703e962fe2343aadd151413a3e2114` 仍为 2,932,774 字节/15 个 RGBA32 原图。独立验证包不包含正式 Art 的全部 Prefab,因此此前的验证不能覆盖这些旧依赖缓存。通过 Unity 官方 `BuildCache.PurgeCache(false)` 清理 SBP 缓存后,正式 Art `20261022.142513` 的 Home 包降为 271,138 字节/0 张源 Texture2D;接着保留缓存的正式增量构建 `20261022.142810` 同样通过,均已暂存到本地 StreamingAssets 与 CDN 目录。 `UiAtlasBuildValidation.Inspect` 在正式 Art 构建完成后检查所有生成图集 bundle 的真实对象。若发现残留原图,`BuildAndStageArt` 自动清理 SBP 缓存,以 `.atlasfix` 版本后缀重建一次;仍有残留则返回失败,禁止暂存异常包。不会仅凭图集 Inspector 或构建映射判断包体正确。`AuditUiAtlasBundle.VerifyProductionGuard` 已确认能检出用户提供的坏包,并验证正式三个图集包均无源纹理;回执 `Tools/output/ui_atlas/size/production_guard.json`。