解决Sprite Atlas打包Asset bundles时重复打包的问题

0x00 前言

在Unity 2018.4.6之前的版本,有一个和SpriteAtlas打AB包有关的常见问题。即当给Sprite Atlas打AB包时,Sprite Atlas Texture可能会被重复打包。你可以在这里查看这个issue。

https://issuetracker.unity3d.com/issues/android-same-atlas-assets-are-being-included-in-asset-bundle-multiple-times-when-bundle-is-built​issuetracker.unity3d.com

本文就来讨论一下如何解决这个问题。

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​docs.unity3d.com

具体如何做呢?首先不勾选“Include in Build”选项,之后再在C#脚本中注册SpriteAtlasManager.atlasRequested 的回调。在这个回调中加载对应的sprite。

https://docs.unity3d.com/ScriptReference/U2D.SpriteAtlasManager-atlasRequested.html​docs.unity3d.com

    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已经修复了这个问题。

posted @ 2020-03-10 05:34  慕容小匹夫  阅读(3853)  评论(2编辑  收藏  举报