[譯]使用AssetBundle Manader

mahua

AssetBundle and the AssetBundle Manager

介紹

AssetBundle允許從本地或者遠程服務器加載Assets資源,利用AssetBundles技術,Assets資源可以放在遠程服務器上,這種技術增加了項目靈活性並且減少項目初始包的大小。

本文介紹AssetBundles並且討論一步一步的介紹怎麼樣使用它,怎樣將資源打包到AssetBundle中,如何使用以及如何處理資源的引用計數,所有這些我們都可以使用AssetBundle Manader來簡化AssetBundle構建、測試和發佈環節。最後會介紹一個使用AB和Variants實際項目的例子。

示例

在讀本文開始之前,最好先從官方下載下載示例

什麼是AssetBundle

AssetBundles是Unity編輯器中在編輯過程中創建的一些文件,這些文件可以在項目運行環境中使用。AssetBundles可以包含的資源文件比如模型,材質,貼圖和場景等等,注意:AssetBundles不能包含腳本!

具體來說,一個AssetBundle就是把資源或者場景以某種方式緊密集合在一起的一個文件。這個AssetBundle文件可以被單獨加載到unity應用程序中。這允許模型、貼圖、音效設置很大的場景這些資源進行流式加載或者異步加載。當然AssetBundle文件也可以本地緩存這樣能夠在程序啓動的時候立馬被加載出來。但AssetBundle技術主要目的就是需要的時候從遠程服務器下載需要的資源。AssetBundle可以包含任何unity可識別的資源文件,甚至包括二進制文件。但就是不能包含腳本文件。

有很多AssetBundle的使用案例。資源在程序中可以被加載和釋放。Post-release DLC可以被輕易的實現。應用程序發佈的時候可以使得包體變得更小,在應用程序啓動的時候加載需要加載的資源。應用程序國際化也會變得相對簡單,我們可以根據玩家的地理位置來判斷加載對應的資源文件。應用程序可以用新的資源文件來達到修復、更新的目的。

AssetBundles怎麼管理和規劃更取決於具體的項目需求。以下有一些基本的規則以便我們更好的理解AssetBundle。
* AssetBundle需要整體的下載和緩存的
* AssetBundle不需要整體的加載到應用程序中
* Assets在AssetBundles中是具有相互依賴性的
* Assets在AssetBundle中可以和其他資源共享依賴
* 每一個AssetBundle都有一些技術開銷,在文件加載上和對文件的管理上
* AssetBundle必須針對平臺進行打包

每一個AssetBundle都是被整體下載的,就算它不會立馬被用到甚至不會在當前場景中用到,它也會佔用下載和磁盤空間資源。

一個AB文件被整體下載之後,我們可以根據需要去加載裏面的資源。

一個資源可能會對其他資源有依賴關係,比如一個模型可以有很多依賴關係,一個遊戲中的模型不僅僅只有網格數據,實際上他是一個擁有很多依賴資源組成的一個共同體。
tank
一個網格模型及其所使用的材質

這個坦克模型的Mesh Render依賴材質資源,材質又依賴貼圖資源。因此這個坦克模型依賴三個文件資源並不是僅僅就一個網格資源

tank
這個坦克模型的資源依賴鏈:模型 > 材質 >紋理

Assets資源之間也是可以相互依賴的,例如:兩個不同的模型可以共享相同的材質,這個材質是依賴貼圖資源。
tank
不同的岩石模型共享相同的材質

在組織AssetBundle結構的時候,需要去平衡開銷,把AssetBundle分成若干個很小的AssetBundle的時候會很耗性能,但如果做成一個大的AssetBundle又會包含許多不需要用到的資源,所以要根據你實際的項目來平衡。

AssestBundle的目錄被以優化的方式編譯到目標平臺上根據目標平臺的導出設置,因爲這樣所以AssestBundles需要導出到各個目標平臺。

依賴關係和依賴管理

關於依賴和依賴管理有幾個重要的點

資源依賴永遠不會丟失。如果這個依賴的assest在AssestBundle被創建時沒有指定任何的AssestBundle,依賴的Assest連同選中的Assest將被添加到AssestBundle,這是非常方便和避免依賴Assest的損失。但是這也可能導致Assets重複。例如,使用兩個岩石上面共享相同的Material,如果岩石列在單獨的AssetBundles和Material沒有顯式地指定一個AssetBundle,將被添加到包含那種Material的兩個 AssetBundles包中。值得注意的事,當這麼做的時候,兩個重複的資源將被存儲在各自的AssetBundles而且依賴關係也破裂了,每個模型的Assest將依賴自己複製出來的Material,沒有了共享Assest的任何優勢。爲了防止這種情況的發生,這些材料需要顯式地指定一個AssetBundle,這可以實現對自己和其他資源的分享。用這種方法,這兩個岩石的AssestBundle將依賴這個岩石Material。

關於依賴信息都存儲在Mamnifest文件中,這個文件很像AssetBundle的資源的table文件。當AB構建時,unity統一生成大量數據,這些數據保存清單的細節,每一個目標平臺都有一個對應的清單,清單列出所有爲當前平臺所需要的AssetBundles存儲,跟蹤和依賴項。使用清單可以查詢所有AssetBundle和他們的依賴項。

有一個關於AssetBundles的特別的設置被叫做 AssetBundle Variants,AssetBundle Variants目的在於一種特殊的情況:在項目中重新映射一個不同Assest中的單個對象,這對於一個需要基於標準分辨率、語言、定位、或用戶偏好選擇不同的Assest特別有用。 AssetBundle Variants可以容納所需的各種Asset的覆蓋所有支持選擇對象和所需的Asset可以根據需要被映射到該對象的選擇的AssetBundle Variants。

AssetBundles文件包含資產文件,如模型、材料、材質和場景。AssetBundles在輯器編輯創建在遊戲中使用,AssetBundles旨在從本地或遠程加載資源。AssetBundles可以變異映射到對象根據現場用戶的偏好。

Working with AssetBundles and the AssetBundle Manager

介紹

對於使用AssetBundles的一個關鍵和重要的工作是對Asset構建測試,通常,AssetBundles會定期的發生改變,所以需要定期的創建AssetBundles,然後將其上傳到一個遠程服務器並測試託管的AssetBundles資源。

本章重點介紹使用AssetBundles Manader。AssetBundle Manager提供了一個高級的API大大提高了工作流。

使用AssetBundles

使用AssetBundles有以下幾步:
* 在編輯器裏面構建AssetBundles
* 上傳AssetBundles到外部存儲
* 在運行時下載AssetBundles
* 從AssetBundles中加載物體
值得注意的是一些AssetBundles可以存儲在本地,以保證立即加載,這有助於防止一個應用程序的安裝不能從遠程下載所有的AB資源。例如,當應用程序沒有訪問下載內容時將從本地AssetBundles加載默認語言和本地數據。

值得注意的是,一個AssetBundles會根據平臺進行打包,AssetBundles根據導入的設置和目標平臺中的設置構建爲目標平臺的AB資源。

在下面的場景中,一種方式就是打包包括地面,沙丘,岩石,仙人掌,樹。這些場景允許包括所有獨立的材質。坦克模型會有自己的AssetBundles,這樣允許改變或者更新玩家信息。想要完成這個坦克的GameObject創建,需要額外依賴兩個AssetBundle一個是材質球,一個是紋理,這麼做對於更新這個材質球和紋理來說,將會造成最小的麻煩,也允許選擇版本或者多個版本,從多個版本中選擇一個需要的AssetBundle來實現平臺,國際化或者目標設備的區分。
tank
一個簡單的場景

在Editor模式下組織和構建AssetBundles,資源必須分配給一個AssetBundle,當查看一個資源,在Inspector面板中右下角可以看到這個AssetBundle的名字和Variant。預覽窗口打開才能看到。
tank
還沒有分配的坦克資源

使用AssetBundle名稱下拉菜單進行分配資源,在這裏要不選擇一個現有的要不創建一個新的。
tank
分配一個資源到AssetBundle

創建一個新的AssetBundle,選擇New並且文本輸入框就會有效讓你輸入名字
如果要移除一個資源,只要選擇None就可以
如果想從列表中刪除一個AssestBundle名字,那必須要把所有的分配給這個AssestBundle的資源的名字都從AssestBundle中刪除掉。然後可以選擇Remove Unused Names,將刪除所有沒被使用的AssestBundle的名字。
tank
AssetBundles名字必須小寫,如果不遵循的話,unity會自動處理成小寫。
tank
這樣AssetBundles名字就被強制改成了小寫。

使用AssetBundles Variants

允許以各種不同的解決方案解決加載問題,包括下載、存儲和更新,一種特定的情況就是AssetBundle 可以依據設備來加載不同的用戶偏好等,這是利用AssetBundle Variants。對場景中的一個物體上同一個資源AssetBundle Variants提供不同的Variants,AssetBundle Variants可以實現替換不同的資源到同一個物體上,只有一種Variants可以在任何時間進行加載。

AssetBundle Variants在很多情況上多可以使用,AssetBundle Variants可以爲不同分辨率的機器或者高低顯卡配置不同的機器或者不同面數的多邊形提供相同的資源,AssetBundle Variants可以根據文本、圖像、紋理和字體可以爲每個受支持的語言不同,地區或主題創建不同的對象。這些資源保存了一系列信息。

以下是AssetBundle的小例子
tank
tank
tank
在上面例子中,兩個文件夾MyAssets-SD和HD同時被分配到myassets的AssetBundle,然後得到一個是別名分別是hd和sd,注意這兩個資源具有相同的名稱和結構,在創建一個資源的時候父目錄被指定到一個AssetBundle上,沒有被指到任何一個AssetBundle上。

值得注意的是下面的圖片的AssetBundle有一個路徑variant/myassets
tank
這將爲名叫myassets的AssestBundle創建一個父菜單,叫variant。一旦一個資源被分配好了之後需要被打包和測試。

一旦資源被指定到 AssetBundle, 這個 AssetBundle 將要被編譯和測試。

使用 AssetBundle Manager

Unity 提供了直接使用 AssetBundle 的底層 API. 但是這篇教程不會覆蓋這些底層 API。關於底層 API 的更多信息,請閱讀這個鏈接。

關於編譯,測試和管理 AssetBundle,這篇教程會專注到 AssetBundle Manager 和它的高層 API 上。

AssetBundle Manager 是一個可下載的,可以安裝在當前 Unity 項目中的包,它提供高層 API 和改進了 AssetBundle 的流程。AssetBundle Manager 可以再 這裏 下載。要在項目中使用 AssetBundle Manager,簡單的將它加到當前的項目的 Asset 文件夾中。

編譯和測試 AssetBundle 可能是在開發過程中的一個痛點。資源會時常的改變。使用底層 AssetBunle API 時,測試需要規律的編譯和上傳 AssetBundle 到一個遠程服務器上,然後從當我的項目建立一個網絡連接來測試遠程服務器上的 AssetBundle。相對於直接操作 AssetBundle 的底層 API, AssetBundle Manager 大幅度的優化了流程。AssetBundle Manager 提供的最核心的功能是一個模擬模式,一個本地的 AssetBundle 服務器和一些快捷的菜單去編譯 AssetBundle 和無間隙地和本地 AssetBundle 服務器合作。

把 AssetBundle Manager 加入到項目之後將會在 Asset 菜單中創建一個叫 AssetBundles 的新菜單項。

這裏寫圖片描述
Assets > AssetBundles

選中 AssetBundles 菜單將會顯示一個小菜單選項。

這裏寫圖片描述

Assets > AssetBundles 菜單項

模擬模式開啓後,允許編輯器不用實際編譯就可以模擬 AssetBundle。要打開模擬模式,選擇 Simulation Mode 菜單項。對勾符號表示模擬模式已經開啓。要關閉模擬模式就再選擇一次菜單項目。然後對勾符號會被移除,模擬模式會被禁用。

當模擬模式開啓後,編輯器會查看哪些資源被指定到了 AssetBundle,然後從項目的 hierarchy 中直接使用他們,就像他們在 AssetBundle 中一樣。但是這些 AssetBundle 不需要編譯。從這點來看,在編輯可以工作到了 AssetBundle 編譯後放到遠程服務器上一樣可以工作。

開啓模擬模式最大的好處是,只要資源被正確地指定到 AssetBundle ,在當前運行的項目測試前不需要停下來去編譯和重新部署 AssetBundle 就可以修改,操作,導入,刪除資源。當開啓模擬模式之後,測試是馬上生效的。

注意 AssetBundle 變體在模擬模式下不支持。測試 AssetBundle 變體,AssetBundle 需要重新編譯和部署。但是,本地的資源服務器支持 AssetBundle 變體。

AssetBundle Manager 也可以開啓一個本地資源服務器來從編輯器或者本地或移動端的 build 來測試。當本地資源服務器開啓後,AssetBundle 必須編譯,然後放到項目跟目錄中,跟 Assets 文件夾同級的 AssetBundles 文件夾裏。
這裏寫圖片描述

本地資源服務器要求的 AssetBundes 文件夾位置

AssetBundles 本地託管之後, 從當前項目中訪問本地資源服務器只需要幾行的代碼就可以方便的訪問。請閱讀 AssetBundle 示例項目中的示例,我們會在教程的下面覆蓋到。

編譯和保存到 AssetBundle 到項目根目錄的 AssetBundles 文件夾中可以從 Assets/AssetBundles 菜單中選擇 Build AssetBundles 來完成。當 Build AssetBundles 被選擇之後, Unity 將會編譯所有有資源指定的 AssetBundle, 然後爲當前的平臺編譯和優化他們,最後保存他們和一個主清單到項目根目錄下的 AssetBundles 文件夾下。如果沒有 AssetBundles文件夾,Unity 會創建一個。在 AssetBundles 文件夾裏,AssetBudle 按照編譯目標平臺來組織。
這裏寫圖片描述

“AssetBundles” 文件夾,按照編譯目標平臺來分組

AssetBundle 被編譯後部署到遠程服務器或者開始本地資源服務器,這些 AssetBundles 可以在運行期下載和插入到項目中。

AssetBundle 練習

練習 AssetBundle, 這教程將會使用 AssetBundle Manager。AssetBundle Manager 會應付 AssetBundle 的加載和他們相關的資源依賴。利用 AssetBundle Manager 來從 AssetBundle 中加載資源,腳本需要使用 AssetBundle Manager 提供的 API。

AssetBundle Manager 的 API 包括:

  • Initialize() 初始化 AssetBundle 清單對象
  • LoadAssetAsync() 從指定的一個 AssetBundle 中加載資源並處理所有的依賴
  • LoadLevelAsync() 從指定的一個 AssetBundle 中加載場景並處理所有的依賴
  • LoadDependencies() 加載指定的 AssetBundle 的所有獨立的 AssetBundle
  • BaseDownloadingURL 設置用來自動下載依賴的基本地址
  • SimulateAssetBundleInEditor 在編輯器中設置模擬模式
  • Vraiants 設置當前的變體
  • RemapVariantName() 根據當前的變體決定正確的 AssetBundle

示例文件放置在 AssetBundle Manager 內的 AssetBundle Sample 文件加下。有 3 個基礎的示例場景和一個高級的示例場景在 AssetBundleSample/Scenes 文件夾下:

  • “AssetLoader” 演示了怎麼樣從 AssetBundle 加載普通資源
  • “SceneLoader” 演示了怎麼樣從 AssetBundle 加載場景
  • “VariantLoader” 演示了怎麼樣加載 AssetBundle 變體
  • “LoadTanks” 更高級,演示了複雜一點的,從同一個場景中加載場景,資源,和 AssetBundle 變體的示例。
    每個場景都各個被非常基礎的腳本驅動着:LoadAsset.cs,LoadScenes.cs,LoadVariants.cs 和 LoadTanks.cs。

當前重申一下 AssetBundle Manager 提供的流程還是很重要的。

爲了能成功的試驗 AssetBundle 的使用,這裏有三種可能的情景:

第一個情景,沒有使用 AssetBundle Manager, AssetBundle 將需要被編譯和部署,所有的測試都會在最終完整準備後完成。在這個場景中,每次項目中資源的改變,都需要編譯和部署新的 AssetBundle。

AssetBundle Manager 在流程上提供了兩個改進。他們是本地資源服務器和模擬模式。

在模擬模式中,編輯器內運行項目時,AssetBundle Manager 會模擬編譯後的 AssetBundles。這是使用 AssetBundle 的最快的流程。只需簡單的使用 “Assets/AssetBundles/Simulation Mode” 菜單打開 “模擬模式”, 然後測試項目。沒有 AssetBundle 會被編譯。儘管如此,要注意 AssetBundle 變體在模擬模式下不工作。還有要注意的是,模擬模式開始後,資源可以再項目中操作,並且改變後的效果在 Sence 視圖中可以看到,而這使用部署後的 AssetBundle 是不行的。

本地資源服務器提供了部署的 AssetBundle 更精確的演示,但是需要 AssetBundle 被編譯和存儲到項目中的默認文件夾。當本地資源服務器開啓之後,被編譯的 AssetBundle 將可以被編輯器和所有運行在本地的,可以通過本地網絡連接編輯器的 build 使用。注意這個是能本地測試 AssetBundle 變體的唯一方式。

要運行示例場景,AssetBundle Manager 必須運行在這些模式中的一種。要成功運行 AssetBundle 變體,AssetBundle 必須被編譯並且本地資源服務器必須被開啓。

示例 1:加載資源

使用 “Asset/AssetBundles/Simulation Mode” 菜單打開模擬模式
打開 “AssetBundleSample/Scenes/AssetLoader” 場景
注意場景是個空的只有一個主攝像機,方向光和遊戲對象 “Loader”
進入 PlayMode
然後會注意到一個 cube 已經從 AssetBundle 加載到場景裏面了
這個場景是被 “LoadAssts.cs” 腳本驅動的。

在腳本編輯器裏面打開腳本 “AssetBundleSample/Scripts/LoadAssets.cs”

腳本里有兩個公共變量: public string assetBundleName; 和 public string assetName;

public string assetBundleName; 保存了要被加載的 AssetBundle 的名字
public string assetName; 保存了要已加載的 AssetBundle 中加載的資源的名字
這個腳本是由一個 Start() 函數和被 Start() 調用的兩個協程組成的。Initialize() 調用了 DontDestoryOnLoad(), 設置了 AssetBundle 的路徑和初始化了 AssetBundle 清單。在 InstantiateGameObjectAsync() 中,如果資源不爲空,AssetBundleManager.LoadAssetAsync() 調用資源和 AssetBundle 的名字。

重點注意下,在 “AssetBundleSample/Assets” 路徑下查看 “MyCube” 資源,會發現 “MyCube” 依賴於 “MyMaterial”,而 “MyMaterial” 依賴於 “UnityLogo”。腳本中只有 “MyCube” 資源被調用,但是所有的依賴資源都被正確的加載了。

AssetBundle 的路徑怎麼設置也值得注意下。當場景在編輯器中或者從一個開發版 Build 中運行時,這段代碼會給本地資源服務器設置 AssetBundle 的位置。(更多關於開發版 Build,請查看發佈 Builds 文檔。)模擬模式開啓後,AssetBundle 會在編輯器中被模擬,這個設置將不會被使用。

對 DontDestoryOnLoad() 作用的理解。雖然在這個非常簡單的腳本中並不是絕對需要它,但是他的存在是假設這個腳本會作爲一個更復雜的項目的 AssetBundle 加載器基礎,它需要在場景變化的以後依然存在。

示例 2:加載場景

使用 “Asset/AssetBundles/Simulation Mode” 菜單打開模擬模式
開始 “AssetBundleSample/Scenes/SceneLoader” 場景
注意場景是個空的只有一個主攝像機,方向光和遊戲對象 “Loader”
開打 PlayMode
然後會注意到一個 cube 和 plane 已經從 AssetBundle 加載到場景裏面了
這個場景被 “LoadScene.cs” 腳本驅動着。

在腳本編輯其中打開 “AssetBundleSample/Scripts/LoadScenes.cs” 腳本。

腳本里有個兩個公共變量:public string sceneAssetBundle; 和 public string sceneName;

sceneAssetBundle; 保持了要加載的 AssetBundle 的名字
sceneName; 保持了要從已加載的 AssetBundle 里加載的場景的名字
這個腳本是有一個 Start() 函數和被 Start() 調用的兩個協程組成的。Initialize() 調用了 DontDestoryOnLoad(), 設置了 AssetBundle 的路徑和初始化了 AssetBundle 清單。在 InitializeLevelAsync() 裏使用 AssetBundleManager.LoadLevelAsync() 調用場景名字和 isAdditive 來請求一個場景。如果場景爲空,AssetManager 會在控制檯顯示出錯誤,然後協程結束。

重點注意下,在 “AssetBundleSample/Assets” 路徑下查看 “MyCube” 資源,會發現 “MyCube” 依賴於 “MyMaterial”,而 “MyMaterial” 依賴於 “UnityLogo”。只有 “TestScene” 場景被請求了。但在 “TestScene” 中的 “Cube” 和所有依賴的資源都被 AssetBundle Manager 正確的加載了。

AssetBundle 的路徑怎麼設置也值得注意下。當場景在編輯器中或者從一個開發版 Build 中運行時,這段代碼會給本地資源服務器設置 AssetBundle 的位置。(更多關於開發版 Build,請查看 發佈 Builds 文檔。)模擬模式開啓後,AssetBundle 會在編輯器中被模擬,這個設置將不會被使用。

對 DontDestoryOnLoad() 作用的理解。雖然在這個非常簡單的腳本中並不是絕對需要它,但是他的存在是假設這個腳本會作爲一個更復雜的項目的 AssetBundle 加載器基礎,它需要在場景變化的以後依然存在。

示例 3:變體

要使用 AssetBundle 變體,需要編譯 AssetBundle, 因爲模擬模式下不支持它。在編譯 AssetBundle 和它的變體錢,確保所有的資源以及被正確地指定 AssetBundle 名字和如果要被 AssetBundle 變體利用到的話,AssetBundle 變體的名字也要指定。
這裏寫圖片描述

同時擁有 AssetBundle 名字和 AssetBundle 變體名字的資源

當所有的資源都指定到 AssetBundle 或者 AssetBundle 變體後,選擇 “Assets/AssetBundles/Build AssetBundles” 菜單來編譯它們。
這裏寫圖片描述

默認情況下,AssetBundle 會根據當前的平臺優化,並編譯進項目跟目錄下的 “AssetBundles” 文件夾內,並按平臺分組。

爲了簡化流程,不部署新編譯出來的 AssetBundle 遠程,需要開啓本地資源服務器。通過 “Assets/AssetBundles/Local AssetBundle Server” 可以開啓本地資源服務器。
這裏寫圖片描述
本地資源服務器應該想其他任何網絡連接一樣受限制,可能是權限需求,防火牆和其他限制。本地資源服務器啓動時會被設置到默認 IP 地址和端口的本地資源訪問的服務器,通常是 http://192.168.1.115:7888/. 這個只是暫時的,它被存儲在 AssetBundleManager/Resources/AssetBundleServerURL 文件裏面。這些信息會被 AssetBundleManager 設置或自動改變,用戶不需要關注它們。
這裏寫圖片描述

當本地資源服務器運行的時候,編譯後 AssetBundle 可以被本地測試。

選擇 “Assets/AssetBundles/Simulation Mode” 確保模擬模式被禁用了
選擇 “Assets/AssetBundles/Local AssetBundle Server” 確保本地資源服務器開啓
打開 “AssetBundleSample/Scenes/VariantLoader”
注意場景是個空的只有一個主攝像機,方向光和遊戲對象 “Loader”
退出 PlayMode (如果在 PlayMode 下)
打開 PlayMode
選擇 “Load HD”
注意同一個 Cube 和 Sprite 加載進場景了,但是材質和他依賴的獨立紋理和 Sprite 紋理卻從不同的 AssetBundle 加載。這些材質有不同的顏色,圖片有更高的分辨率。
這個場景是被 “LoadVariant.cs” 腳本驅動的。

從編輯器中打開 “AssetBundleSample/Scripts/LoadVariants”。

這個腳本跟 “LoadScenes.cs” 幾乎差不多。主要的區別就是用來區別需要加載的 AssetBundle 變體的變量和設置當前變體的代碼。還有用來創建 UI 按鈕的額外的代碼。

public string variantSceneAssetBundle; 保存要加載的 AssetBundle 的名字
public string variantSceneName; 保存要從已加載的 AssetBundle 中加載的場景名字
private string[] activeVariants; 保存用來區分需要加載的 AssetBundle 變體的 AsssetBundleVariantNames
private bool bundlesLoaded 用來在加載完資源之後隱藏 UI
腳本由一個 BeginExample() 函數和被 Start() 調用的兩個協程組成。 BeginExample() 在 OnGUI()函數中 被 Load HD 或者 Load SD 按鈕調用。Initialize() 調用了 DontDestoryOnLoad(), 設置了 AssetBundle 的路徑和初始化了 AssetBundle 清單。在 BeginExample() 方法裏,在調用 Initialize() 和 InitializeLevelAsync() 之間,當前的變體被設置了。這裏被設置的值從靠 OnGUI 裏的 “Load HD” 或者 “Load SD” 按鈕創建的。在 InitializeLevelAsync() 裏使用 AssetBundleManager.LoadLevelAsync() 調用場景名字和 isAdditive 來請求一個場景。如果場景爲空,AssetManager 會在控制檯顯式出錯誤,然後協程結束。

這裏需要重視的是 AssetBundle 變體是怎麼樣加載的。activeVariants 數組包含了所有可能的 “激活的” 變量名列表。這個數組用來設置 AssetBundleManager.ActiveVariants 屬性。當加載一個含有變體的 AssetBundle 時,AssetBundle Manager 將會選擇在 ActiveVariants 屬性裏含有 “激活” 的變體名字的 AssetBundle。當前的示例中,ActiveVariants 屬性只包含一個元素。當前的變體要麼是 “sd”,要麼是 “hd”。在 ActiveVariants 屬性中有多個實體是有可能的。比如,可能有下面一些 AssetBundle: my-material.sd,my-material.hd, my-text.english,my-text.catalan,my-text.welsh。ActiveVariants 屬性可以包含 “hd” 和 “danish” 兩者或者 “sd” 和 “english” 等等任何可以有其他可能組合的變體名。這種方式下,AssetBundle Manager 分開可以加載 hd/sd 圖片和語言選擇。

有些規則值得注意下。如果,因爲一些因素,有一些指定了變體的 AssetBundle,但是在 ActiveVariants 屬性裏沒有 “激活” 的變體名 - 比如當前例子中的 “sd” 或者 “hd” 不在 ActiveVraiants 屬性中 - AssetBundle Manager 將會簡單的選擇第一個它發現的正確名字的 AssetBundle 而忽略變體名。再如果,又因爲一些因素,在 ActiveVariants 屬性裏對同一個 AssetBundle 集合有多個 “激活” 的變體名 - 比如, 在當前的例子裏,“sd” 和 “hd” 都在 ActiveVariants 屬性裏 - AssetBundle Manager 將選擇在 ActiveVariants 屬性中的第一個變體名。

示例 4:坦克示例

這個更復雜的示例將包括這篇文章中的所有內容,包括從 AssetBundle 中加載場景和爲分辨率,內容和位置加載 AssetBundle 變體。

選擇 “Assets/AssetBundles/Simulation Mode” 確保模擬模式被禁用了
選擇 “Assets/AssetBundles/Local AssetBundle Server” 確保本地資源服務器開啓
打開 “AssetBundleSample/Scenes/TanksLoader”
注意場景是個空的只有一個主攝像機,方向光和遊戲對象 “Loader”
進入 PlayMode
選擇一個分辨率,風格和語言
注意在 UI 裏的選擇項就是加載的資源
如果沒有顯式的選擇一個,AssetBundleManager 將自動選擇(基於上面的原則)一個並且在命令行輸出一個警告。
場景靠 “LoadTanks.cs” 腳本驅動。

在編輯器裏面打開 “AssetBundleSample/Scripts/LoadTanks.cs” 腳本。

這個腳本與 “LoadScenes.cs” 和 “LoadAssets.cs” 非常像。腳本使用代碼去加載依賴變體的場景和一樣依賴變體的額外的遊戲對象。也有一些額外的代碼創建 UI 按鈕。

  • public string sceneAssetBundle; 保存攜帶場景的 AssetBundle 的名字
  • public string sceneName; 保存要從已加載的 AssetBundle 中加載的場景名字。
  • public string textAssetBundle; 保存攜帶文字資源的 AssetBundle 的名字
  • public string textAssetName; 保存要從已加載的 AssetBundle 中加載的文字資源的名字
  • private string activeVariants; 保存要傳給 AssetBundleManager 的 ActiveVariants
  • private bool bundlesLoaded; 用來資源加載之後隱藏 UI
  • private bool sd, hd, normal, desert, englisth, danish; 保存用來設置 ActiveVariants 的值
  • private string tankAlbedoStyle, tankAlbedoResolution, languge; 保存用來設置 ActiveVariants 的值

腳本由一個 BeginExample() 函數和被 Start() 調用的兩個協程組成。 BeginExample() 在 OnGUI()函數中 被 “Load Scene” 按鈕調用。Initialize() 調用了 DontDestoryOnLoad(), 設置了 AssetBundle 的路徑和初始化了 AssetBundle 清單。在 BeginExample() 方法裏,在調用 Initialize() 和 InitializeLevelAsync() 之間,當前的變體被設置了。這裏被設置的值從靠 OnGUI 裏的 “Load Scene” 按鈕創建的。在 InitializeLevelAsync() 裏使用 AssetBundleManager.LoadLevelAsync() 調用場景名字和 isAdditive 來請求一個場景。如果場景爲空,AssetManager 會在控制檯顯式出錯誤,然後協程結束。在 InstantiateGameObjectAsync() 中資源和 AssetBundle 名字被 AssetBundleManager.LoadAssetAsync() 調用。如果調用的資源不爲空,它會被實例化。如果 AssetBundle 不能被加載或者資源不能被請求,控制檯會打印出錯誤來。

這小結要注意的內容是,多個 資源,AssetBunle 和 AssetBunle 變體怎麼被訪問和加載進場景裏,和怎麼樣在運行期設置這些值。

友情提醒

新手翻譯,翻譯不對之處多多見諒!

參考鏈接

工程下載

https://git.oschina.net/dingxiaowei/AssetBundleManager.git

關於譯者

  var aladdin = {
    nickName  : "Aladdin",
    site : "http://blog.csdn.net/dingxiaowei2013"
    u3d QQ Group :159875734
  }

更多關於AB的優質文章和參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章