当前位置: 首页 > news >正文

Unity MyFramework 用法说明(二十五):使用 AtlasManager 统一管理图集与 Sprite 引用

Unity 的图片最终通常会被打进图集,但业务代码仍然需要处理图集加载、Sprite 查找、引用持有和资源释放。

MyFramework 使用AtlasManager同时封装SpriteAtlas v2和传统 Multi Sprite 图集,并通过AtlasRef管理图集引用,避免图片仍在使用时图集被提前卸载。

项目地址:

https://github.com/ZHOURUIH/MyFramework

一、AtlasManager 解决什么问题

直接使用 Unity 图集时,业务层需要考虑:

图集资源如何加载 如何通过名称查找 Sprite 多个界面共享图集时何时卸载 异步加载完成时界面是否还存在 SpriteAtlas 在真机上如何响应 atlasRequested TexturePacker 图集和 SpriteAtlas 如何使用统一接口

AtlasManager将这些操作统一为:

加载图集 ↓ 获得 AtlasRef ↓ 通过名称获取 Sprite ↓ 界面或对象持有 AtlasRef ↓ 使用结束后释放引用 ↓ 引用数量为 0 时自动卸载

业务层不需要区分当前图集来自SpriteAtlas,还是一张设置为 Multiple 的纹理。

二、同步加载图集

图集路径相对于:

Assets/GameResources

并且必须带后缀。

例如图集位于:

Assets/GameResources/UI/Common.spriteatlasv2

加载方式为:

using static FrameBaseHotFix; protected AtlasRef mCommonAtlas; protected void loadAtlas() { mCommonAtlas = mAtlasManager.getAtlas( "UI/Common.spriteatlasv2"); if (mCommonAtlas == null || !mCommonAtlas.isValid()) { return; } Sprite buttonSprite = mCommonAtlas.getSprite("ButtonNormal"); }

getAtlas()首先检查图集是否已经加载。

已经存在时,只创建一份新的AtlasRef;不存在时,才通过ResourceManager加载图集资源并解析其中的 Sprite。

三、AtlasRef 表示一次独立引用

AtlasRef并不只是包装AtlasBase,它还会为每个持有者生成独立凭证:

public void setAtlas(AtlasBase atlas) { mAtlas = atlas; mToken = generateToken(); mAtlas.addReference(mToken); }

图集内部保存全部引用凭证:

protected HashSet<long> mReferenceTokenList = new();

同一个图集被三个界面使用时,结构类似:

Common.spriteatlasv2 ├── AtlasRef:主界面 ├── AtlasRef:背包界面 └── AtlasRef:商店界面

关闭背包界面,只会释放背包自己的引用,不会影响主界面和商店界面。

因此,不要把一份AtlasRef同时交给多个生命周期不同的对象。

每一个独立持有者,都应该通过getAtlas()获得自己的引用。

四、释放图集引用

不再使用图集时调用:

mAtlasManager.unloadAtlas( ref mCommonAtlas);

unloadAtlas()会:

校验 AtlasRef 是否有效 移除当前引用凭证 回收 AtlasRef 把变量设置为 null

不要直接卸载底层纹理或SpriteAtlas

Resources.UnloadAsset(texture); Object.Destroy(sprite);

这些操作会绕过AtlasManager的引用记录,可能让其他仍在显示图片的界面失去资源。

五、为 UI 动态切换图集

需要运行时切换图片的节点,应使用:

myUGUIImage

例如一个专门显示物品图标的节点:

public class UIItemDetail : LayoutScript { protected myUGUIImage mItemIcon; protected AtlasRef mItemAtlas; public override void assignWindow() { newObject( out mItemIcon, "Background/ItemIcon"); } public override void onGameState() { base.onGameState(); mItemAtlas = mAtlasManager.getAtlas( "UI/Item.spriteatlasv2"); mItemIcon.setAtlas(mItemAtlas, true); mItemIcon.setSpriteName("Item_Sword"); } public override void onHide() { mItemIcon.setAtlas(null, true); mAtlasManager.unloadAtlas( ref mItemAtlas); base.onHide(); } }

myUGUIImage.setAtlas()只负责切换当前使用的图集,并不会接管外部传入图集的释放。

因此,动态加载的AtlasRef仍然需要由业务对象保存,并在生命周期结束时主动卸载。

六、为什么需要 ImageAtlasPath

运行时只通过一个Sprite,无法可靠得知它来自哪个资源路径或哪个图集。

所以 MyFramework 为需要切换图片的节点提供了:

ImageAtlasPath

它会在编辑模式下记录当前图片所在图集:

public string mAtlasPath;

myUGUIImage.init()中会读取这个路径,并获取初始图集引用:

Image ↓ ImageAtlasPath 记录图集路径 ↓ myUGUIImage 初始化 ↓ AtlasManager 加载初始图集

因此,需要使用myUGUIImage动态切换 Sprite 的节点,应确保:

存在 Image 组件 存在 ImageAtlasPath 组件 ImageAtlasPath 中记录的路径正确

普通静态图片不需要在代码中切换时,可以继续使用myUGUIImageSimple

七、异步安全加载图集

图集较大,或者界面需要异步打开时,可以使用:

getAtlasAsyncSafe

示例:

protected AtlasRef mItemAtlas; protected void loadAtlasAsync() { mAtlasManager.getAtlasAsyncSafe( this, "UI/Item.spriteatlasv2", (atlas) => { mItemAtlas = atlas; mItemIcon.setAtlas( mItemAtlas, true); mItemIcon.setSpriteName( "Item_Sword"); }); }

第一个参数需要实现IRecyclable

开始加载时,框架会记录对象当前的AssignID。完成后再次检查:

AssignID 没有变化 执行回调 对象已销毁或被对象池重新分配 不执行旧回调

这样可以避免界面已经关闭后,旧的图集加载结果又设置到被复用的界面对象上。

八、相同图集的异步请求会被合并

AtlasManager内部维护:

protected Dictionary< string, List<AtlasLoadParam>> mLoadRequestList = new(); protected Dictionary< string, List<AtlasLoadParam>> mLoadingList = new();

当多个对象同时请求同一个图集时,不会重复发起多次资源加载。

流程为:

界面A请求 Item.spriteatlasv2 ↓ 开始加载图集 界面B再次请求同一路径 ↓ 只把回调加入等待列表 图集加载完成 ↓ 创建一个 AtlasBase ↓ 依次为所有请求创建 AtlasRef ↓ 分别执行回调

同时加载的不同图集数量最多为:

protected const int MAX_LOADING_COUNT = 20;

超过上限的请求会暂时保留,等待其他图集完成后再开始。

九、统一支持两种图集格式

图集加载完成后,AtlasManager会根据后缀决定解析方式。

SpriteAtlas v2

后缀为:

.spriteatlasv2

创建:

AtlasUGUI atlas = new(mainAsset);

然后通过:

spriteAtlas.GetSprites(spriteList);

取出图集中的全部 Sprite,并以名称缓存。

Multi Sprite 图集

其他包含多个 Sprite 的纹理会创建:

AtlasTP atlas = new(mainAsset);

加载结果中:

Texture2D 用于保存实际图集纹理 Sprite 逐个加入名称缓存

最终两者都继承:

AtlasBase

业务层始终使用:

atlasRef.getSprite(spriteName);

不需要为不同图集格式分别编写代码。

十、图集如何自动卸载

AtlasManager每隔两秒检查一次已加载图集:

protected const float CHECK_INTERVAL = 2.0f;

满足以下条件时自动销毁:

AtlasRef 引用数量为 0 并且 图集不在常驻列表中

核心判断为:

if (atlas.getReferenceCount() == 0 && allowUnloadAtlas(atlasPath)) { atlas.destroy(); mAtlasList.remove(atlasPath); }

销毁时会:

清空 Sprite 名称缓存 释放主资源 ResourceRef 从 AtlasManager 中移除图集

高频使用、不希望反复卸载的图集可以设置为常驻:

mAtlasManager.addDontUnloadAtlas( "UI/Common.spriteatlasv2");

常驻图集仍然需要正确释放AtlasRef,只是引用归零后不会被自动卸载。

十一、真机上的 SpriteAtlas 加载

Unity 在运行时可能通过:

SpriteAtlasManager.atlasRequested

请求某个SpriteAtlas

AtlasManager.init()中会注册:

SpriteAtlasManager.atlasRequested += onAtlasRequested;

收到请求后,框架通过:

AtlasPathConfig.txt

把图集名称转换为资源路径,再使用ResourceManager加载对应的SpriteAtlas

这一步主要用于保证真机上 Prefab 或场景中的 Sprite 能正确绑定到动态加载的图集。

AtlasPathConfig.txt应由框架的资源流程生成和维护,业务代码不需要手动响应atlasRequested

十二、总结

MyFramework 的图集管理流程是:

加载 SpriteAtlas 或 Multi Sprite ↓ 统一解析为 AtlasBase ↓ 缓存全部 Sprite ↓ 为每个持有者创建 AtlasRef ↓ 通过名称获取 Sprite ↓ 使用结束后释放 AtlasRef ↓ 引用归零后自动卸载图集

常用接口包括:

mAtlasManager.getAtlas(...); mAtlasManager.getAtlasAsyncSafe(...); atlasRef.getSprite(...); mAtlasManager.unloadAtlas(ref atlasRef); mAtlasManager.addDontUnloadAtlas(...);

AtlasManager的核心并不只是通过名字查找图片,而是把图集加载、格式兼容、异步请求合并、引用计数和自动卸载统一起来。

业务层只需要明确使用哪个图集、获取哪张图片,以及什么时候结束持有。

http://www.jsqmd.com/news/1322549/

相关文章:

  • 彻底解决Flash Attention安装失败:CUDA环境与编译错误全解析
  • UniApp安卓真机调试全攻略:从白屏到插件集成的避坑指南
  • 贝叶斯统计与贝叶斯优化:严谨而直观的公式导读
  • 2026 年值得关注的去水印方法:免费软件与线上工具实测 - 免费软件工具方法教程
  • 如何写出一篇一流论文?学会六位《Nature》专家经验,再结合AI高效辅助,轻松突破写作瓶颈!
  • 如何利用ManiSkill GPU并行仿真平台优化机器人学习性能
  • 旧房改造玄关柜定制避坑指南|我乐家居一体化玄关定制重塑入户空间 - 甄选测评官
  • 网上投票怎么弄?2026永久免费教程|西瓜评选批量导入+强防刷一步到位 - 投票小程序
  • 中小微企业免费进销存软件选型指南:五款主流工具深度横评
  • 7个Anki批量操作技巧:快速提升学习效率的终极指南
  • HFSS仿真常见错误排查指南:从几何模型到求解设置的实战解析
  • aardio动态网格布局实现:从原理到实战的完整指南
  • Blog-AIAssistant:程序员的智能健康管理与知识管理终极解决方案
  • CTF压缩包攻击实战:从基础工具到高级破解技巧全解析
  • Claude 模型被利用,数十年安全漏洞或让 DNA 档案遭篡改
  • 三国杀自由行:一个浏览器就能玩转的桌游革命
  • 2026咸宁测甲醛,靠谱服务商这样选更省心 - 甄选测评官
  • NoSleep:简单免费的Windows防休眠终极解决方案,彻底告别自动锁屏烦恼
  • 3步实现企业级Keycloak容器化部署:从评估到上线的完整指南
  • 从Web 1.0到Web 3.0:互联网技术架构演进与未来趋势解析
  • Stable-Video-Diffusion模型终极实战指南:5个步骤快速部署AI视频生成
  • 终极AI系统提示词解密指南:如何获取主流AI模型的完整配置手册 [特殊字符]
  • 2026年上海衬胶阀门行业优质供应商实力解析:上海疆昊阀门有限公司全产业链运营与专业化服务 - 卓企推荐
  • mheatmap高级教程:RMS置换分析如何揭示数据中的隐藏模式
  • Quick BI中lod_fixed函数详解:解决多粒度计算与跨层级分析难题
  • Qwythos-27B-v1震撼发布:终极开源推理模型如何突破270亿参数限制?
  • CLI-Anything:为AI智能体时代重构软件接口的革命性框架
  • 道德经道影书斋注释版050|出生入死
  • Node.js操作飞书多维表格API:从权限配置到CRUD实战指南
  • [2026]松滋道路救援汽车拖车各区服务商大全,就近派单快速到 - 甄选测评官