英文原文:https://thegamedev.guru/unity-addressables/spriteatlas-save-memory/
您在游戏中使用 Unity UI 还是 Sprite Renderer?
您可能听说过 Unity SpriteAtlas 功能……
SpriteAtlas 可帮助您减少在 Unity 中渲染 UI 或 sprites 时的游戏绘制调用。
然而,sprites 图集是难以驯服的野兽,可以咬掉你的手。
例如,对 SpriteAtlas Sprite的单个引用将使您将整个地图集加载到内存中,即使您只需要一个Sprite……或者即使您没有主动使用Sprite本身。
只是引用可以使您的内存使用和加载时间猛增。
你想要的是对 Unity 如何管理你的 SpriteAtlas 的内存发表意见,这样你就不会扼杀你的游戏性能预算。
好吧,您可以通过使用超级 Unity Addressables 和 SpriteAtlas wombo combo 来做到这一点。
他们可以一起工作吗?
你打赌他们可以。
长话短说:
- 仅将您的 SpriteAtlas 标记为可寻址资产
- 使用 AssetLoadAsync 从可寻址的SpriteAtlas加载特定的Sprite……
- 通过 AssetReferenceAtlasedSprite 变量,或
- 通过硬编码的子资产路径,例如“myspriteatlaskey [myspritename]
- 使用 Addressables.Release 卸载你的Sprite
内容
- 谁是拉尔夫,为什么拉尔夫生气?
- 问题:Unity SpriteAtlas 的默认行为
- 升级:Unity SpriteAtlas 和 Addressables
- 下一步是什么?
谁是拉尔夫,为什么拉尔夫生气?
这是夏天一个阳光明媚的星期二。
你醒来,出于某种原因,你感到非常高兴。
您很高兴开始唱一首关于今天您将如何改进游戏架构的歌曲。
已经决定了。 你别再胡扯了。
所以你阅读了一些文档并决定了下一步:你将把你的繁多的Sprite放在一个单独的 SpriteAtlas 中。
你想,这一定是个好主意。
正如您预期的那样,您设法减少了:
- 绘制调用 10 倍
- 内存使用(RAM + 闪存)。
因此,您点击了提交按钮,收工了。
这是美好的一天……您用菠萝披萨奖励自己*。
- 我的意大利女友不赞成这样做。
然而,就在你即将入睡时,你的手机响了……响亮。
“什……是谁?”你问,声音在颤抖。
“我是你的老板,拉尔夫。 你搞砸了游戏。 你永远被罐头了”。
听到这些话会让你昏迷很长时间5秒,在此过程中失去耐力点。
“什……等什么……?” 你几乎没来得及问,因为一股诡异的寒意顺着你的脊椎流下,冷汗顺着你的额头流下。
“不,我在开玩笑,你还没有被解雇。 但是,让你的屁股在这里并修复分数屏幕中发生的崩溃,“拉尔夫在断开连接之前说道。
由于严重的花粉症症状,您启动了 PC 并等待 10 分钟让 Unity 加载您的项目。
迫不及待,你会进入比分屏幕和 BAM。
内存使用量爆炸了……
因为 Unity 在最糟糕的时刻加载了整个精灵图集
经过一些调试后,您意识到您遗漏了一个您甚至没有绘制的精灵的引用。
精灵引用就在那里。
对你微笑。
等待合适的时机让你陷入困境。
而且……那个Sprite真的让你着迷。
但是您修复了它并吸取了重要教训:
问题:Unity SpriteAtlas 的默认行为
当您引用位于 SpriteAtlas 中的Sprite时,您将整个Atlas加载到内存中,然后使用Sprite占据的特定区域。
以非最佳方式打包和引用您的 sprite 可能会产生严重的副作用,例如崩溃和加载时间增加。
在处理 sprite atlases 时,您在 Unity 中要做的第一件事是以最大化 sprite 经济性的方式设计您的 sprite atlases。
这意味着,您想将同时使用的精灵打包在一起。
但是即使你完美地打包了你的精灵,你仍然可能会遇到麻烦。
例如,你可能会过早加载整个精灵图集……当你真的负担不起时。
想象一下,你有一个复杂的 UI 系统,有大量的 sprites和 sprite atlases……像模拟人生这样的游戏有 4000 多个扩展和数百万个不同的项目预览 sprites。
事实是这样的:你不能付出同时将所有这些sprite atlases加载到内存中的代价。 然而,您需要在某些用户交互时加载它们。
坏消息:只是稍后引用它们(“以防万一”)实际上会立即将它们加载到内存中,导致邪恶的最终老板拉尔夫解雇你。
但是你可以保留你的薪水:我们可以使用 Addressables 按需加载/卸载 sprite atlases 上的 sprite ,无论你有什么引用。
简而言之:让您选择何时以及如何加载这些精灵图集。
升级:Unity SpriteAtlas 和 Addressables
使用 Addressables 从 sprite atlases 加载/卸载 sprite 变得很容易。
只需将 SpriteAtlas(不是单个精灵)标记为可寻址资产即可。
这是您正在寻找的 wombo combo:
public class AddressableImage : MonoBehaviour
{
public AssetReferenceAtlasedSprite addressableSprite;
IEnumerator Start()
{
var image = GetComponent<Image>();
yield return new WaitForSeconds(6);
// Option A) Load atlas & take a sprite
var asyncOperationHandle = addressableSprite.LoadAssetAsync<Sprite>();
// Option B) Addressable asset key + subasset selection
//var asyncOperationHandle = Addressables.LoadAssetAsync<Sprite>("Sprite Atlas[TheGamedevGuru-Sample-1]");
yield return asyncOperationHandle;
image.sprite = asyncOperationHandle.Result;
// Release at some point
yield return new WaitForSeconds(6);
image.sprite = null;
Addressables.Release(asyncOperationHandle);
}
}
让我把它从 C# 翻译成英语……
上面写着:
写给Unity的信
亲爱的Unity,
感谢您没有像默认情况下那样自动加载此精灵图集。
我知道如果我想控制其内存生命周期,您总是告诉我使用 Addressables,所以这正是我所做的(第 3 行)。
现在,时机已到。 请异步加载此精灵(第 11/14 行)并将其分配给这个受祝福的 UI 图像(第 17 行)。
但不要忘记:几秒钟后,当我不再需要它时,我会要求你从内存中卸载整个东西(第 22 行)。
谢谢,
您快乐的 Unity Pro 订阅者
结果?
你只有在真正需要的时候才付出代价,因为 Addressables 让你自己管理这个内存。
使用子资产引用可能性(在检查器和代码中),现在比以往任何时候都更容易做到这一点。
通过将 addressables 与 sprite atlases 一起使用,您将减少绘制调用和加载时间。
反过来,更好的性能会让您的玩家更深入地参与您的游戏。
谢谢阅读