1. 程式人生 > >解決Sprite Atlas打包Asset bundles時重複打包的問題

解決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已經修復了這個問題。