AssetBundle的加載與卸載方式摘要
文中Object和Asset兩個詞用的比較混亂,但是Unity的官方英文文檔裏就是不停地在用這兩個詞,所以這裏也沒有替換爲中文。
用於加載AssetBundle的API
AssetBundle.LoadFromFile[Async]()
- 首選方法(在速度、磁盤使用和內存佔用方面都很高效)
- 適用於從本地存儲加載未壓縮或LZ4壓縮的AssetBundle
- 使用LZMA壓縮的AssetBundle會被解壓到內存中
- 使用LZ4壓縮或未壓縮的AssetBundle會直接從磁盤讀取
AssetBundle.LoadFromStream[Async]()
- 適用於從流式數據中加載AssetBundle
- 使用LZMA壓縮的AssetBundle會被解壓到內存中
- 使用LZ4壓縮或未壓縮的AssetBundle會直接從流數據中讀取
- 加載過程中不能Dispose流式對象
UnityWebRequest[AssetBundle].GetAssetBundle()
- 適用於從遠程下載AssetBundle
- 能夠緩存已下載的AssetBundle以便重用
- 緩存系統中的AssetBundle僅以文件名進行標識而不是使用URL
AssetBundle.LoadFromMemory[Async]()
- 不推薦使用
- 會產生AssetBundle的冗餘副本
方括號
[]
用來表示類或方法的其他版本,下同。
用於從AssetBundle中加載Asset的API
AssetBundle.LoadAsset[Async]()
- 首選方法
- 適用於加載AssetBundle中的單個Object
- 當要加載AssetBundle中超過66%的Object時,考慮使用LoadAllAssets()方法
AssetBundle.LoadAllAssets[Async]()
- 適用於一次性加載AssetBundle中的全部Object
- 比多次調用LoadAsset()更快
AssetBundle.LoadAssetWithSubAssets[Async]()
- 適用於從AssetBundle中加載含有多個嵌套Object的複合Asset
- 如果要加載的Object都來自於同一Asset並且他們和很多不相關的其他Object放在同一AssetBundle內,那麼應該使用此方法
當Object被加載完成後,會調用它的
Awake()
方法,並在下一幀對Unity引擎可用。
用於查詢AssetBundle依賴的API
AssetBundleManifest.GetAllDependencies()
- 返回被AssetBundle所直接和間接依賴的所有AssetBundle的名稱
AssetBundleManifest.GetDirectDependencies()
- 返回被AssetBundle所直接依賴的AssetBundle的名稱
加載AssetBundle時不能自動加載該AssetBundle所依賴的其他AssetBundle,但從AssetBundle中加載Asset時能夠自動加載該Asset所依賴的其他Asset。
AssetBundle和其所依賴的AssetBundle的加載順序並不重要,只要在從其中加載Asset時保證被依賴的AssetBundle已經加載即可。
用於卸載AssetBundle的API
AssetBundle.Unload()
- 卸載此AssetBundle
- 如果參數
unloadAllLoadedObjects
傳入false
- 此AssetBundle中的Asset的壓縮數據文件將被卸載
- 無法再從此AssetBundle中加載任何Object
- 已經從此AssetBundle中加載的Object仍能正常工作
- 如果參數
unloadAllLoadedObjects
傳入true
- 首選方式
- 所有從此AssetBundle中加載的Object都將被銷燬
- Scene中對這些Object的引用將會丟失
AssetBundle.UnloadAllAssetBundles()
- 卸載當前已加載的所有AssetBundle
- 參數作用與
AssetBundle.Unload()
方法的參數相同
Resources.UnloadUnusedAssets()
- 卸載所有未被使用的Asset
Asset的清理會在特定時期觸發,但也可以手動觸發。
當從AssetBundle中加載的Object被從活動的Scene中移除時,Unity不會自動將其卸載。
卸載AssetBundle但不卸載從其中加載的Object將會破壞此AssetBundle與Object之間的鏈接關係。如果之後再次加載了此AssetBundle並加載同一Object,內存中就會產生新的Object副本,而不是使用未被卸載的那個Object。
最好將那些需要同時加載或者更新的Object打包到同一個AssetBundle中。
Asset分配策略
- AssetBundle太少
- 增加運行時內存佔用
- 增加加載時間
- 需要下載的內容更大
- AssetBundle太多
- 增加構建時間
- 使開發更復雜
- 增加整體下載時間
- 分組Object的基本策略
- 根據邏輯實體分組
- 根據Object類型分組
- 根據同時使用的內容分組
- 選擇AssetBundle壓縮方式時需要考慮的問題
- 加載時間:從本地加載未壓縮的AssetBundle要比加載壓縮過的AssetBundle快得多
- 構建時間:LZMA和LZ4壓縮文件的速度非常慢
- 應用大小:如果AssetBundle被附帶在項目中,將它們壓縮可以減小應用程序的體積
- 內存佔用:如果考慮內存佔用量,請使用不壓縮或者以LZ4壓縮的AssetBundle
- 下載時間:如果AssetBundle很大或者用戶網絡帶寬有限,那可能需要壓縮
- 如果AssetBundle中的主要內容是使用緊密壓縮算法進行壓縮的DXT壓縮紋理,那麼這個AssetBundle不應該再被壓縮
- 強烈建議開發者不要在WebGL項目中使用壓縮的AssetBundle
AssetBundle補丁更新
使用AssetBundle進行補丁更新只需簡單的使用新AssetBundle替換已有的AssetBundle即可。如果正在使用UnityWebRequest[AssetBundle]
管理應用程序的AssetBundle緩存,那麼傳遞一個不同的version
參數即可觸發下載新的AssetBundle。
補丁系統需要維護兩個信息列表:
- 含有當前已下載的AssetBundle及其版本信息的列表
- 含有服務器上的AssetBundle及其版本信息的列表
補丁系統應該下載服務器上的AssetBundle的信息,然後與本地的AssetBundle信息進行比對,重新下載缺失的和版本信息發生變化的AssetBundle。