0x00 前言
在Unity 2018.4.6之前的版本,有一个和SpriteAtlas打AB包有关的常见问题。即当给Sprite Atlas打AB包时,Sprite Atlas Texture可能会被重复打包。你可以在这里查看这个issue。
本文就来讨论一下如何解决这个问题。
0x01 The Issue
首先,我会演示一下这个issue。如下图所示,有4个sprite,分别为Icon1, Icon2, Icon3 以及 SF Window(来自Unity Samples: UI)。将它们存放到一个叫 new sprite atlas 的新Sprite Atlas中。同时有一个uGUI的Panel使用了其中的一些Sprite来渲染UI元素。
之后使用AssetBundles-Browser分别对UI Canvas和Sprite Atlas打包。
现在,我们可以继续使用另一个和Assetbundle相关的很赞的工具:
https://github.com/faelenor/asset-bundle-analyzer
来对刚刚打包的Assetbundle的内容进行分析。顺便说一下,这个工具是由一位Developer Relations Engineer 开发的,如果有反馈可以到他的工程仓库提交issue。并且这个工具需要Python2.7来执行,同时由于它的结果会保存到数据库中,因此最好有一个DB工具例如DB Browser for SQLite来查询数据库。
python analyzer.py /Applications/Unity/Unity.app/Contents/Tools ~/projects/MyGame/AssetBundles
Ok,现在我们来看一下我们得到的数据。主表叫做“objects”,每一行数据都来自Assetbundle中的每一个asset。我们可以通过“object_view”视图来查看其内容。
如上图所示,canvas和new sprite atlas 这2个Assetbundle都包含了同一个资源——spriteasset texture。我们可以在Editor中找到这张texture。
Editor 中的预览
0x02 The Solution
那么现在我们要如何解决这个问题呢?这个问题其实是由于所谓的“SpriteAtlas dependencies”所导致的。也就是SpriteAtlas 依赖问题。在SpriteAtlas的inspector编辑器上有一个叫做“Include in Build”的选项。这个选项开启时,会建立具体的sprite和SpriteAtlas的依赖关系,也就是说SpriteAtlas资源会随着具体的sprite走,就像Unity中其他asset之间产生依赖那样。
相反,如果不勾选该选项,sprite会解除它和SpriteAtlas的依赖关系。因此,SpriteAtlas也就不会自动添加到sprite所在的ab中。之后或在运行时,就可以使用所谓的“LateBinding”来加载和绑定对应的sprite了。
https://docs.unity3d.com/Manual/LateBinding.html
具体如何做呢?首先不勾选“Include in Build”选项,之后再在C#脚本中注册SpriteAtlasManager.atlasRequested 的回调。在这个回调中加载对应的sprite。
https://docs.unity3d.com/ScriptReference/U2D.SpriteAtlasManager-atlasRequested.html
void OnEnable()
{
SpriteAtlasManager.atlasRequested += RequestAtlas;
}
void OnDisable()
{
SpriteAtlasManager.atlasRequested -= RequestAtlas;
}
void RequestAtlas(string tag, System.Action<SpriteAtlas> callback)
{
var ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/new sprite atlas");
var sa = ab.LoadAsset<SpriteAtlas>(tag);
callback(sa);
}
现在,再用AssetBundle Analyzer这个工具来查看一下这次AssetBundle中的数据吧。可以看到此时只有一个spriteatlas的texture打包进了ab中。
ok,还记得本文一开始时说过的吗?是的,这是一个Unity2018.4.6之前的issue。在Unity 2018.4.6中,Unity已经修复了这个问题。