【轉】Unity資源機制

原文地址:http://gad.qq.com/article/detail/7180936
作者:Loki+X
Unity資源機制
1、概述
  本文意在闡述Unity資源機制相關的信息,以及一些關于個人的理解與試驗結果。另外還會提及一些因機制問題可能會出現的異常以及處理建議。大部分機制信息來源于官方文檔,另外為自我驗證后的結果。

2、資源
概述
   Unity必須通過導入將所支持的資源序列化,生成AssetComponents后,才能被Unity使用。以下是Unity對Assets的描述:
  Assets are the models,textures,sounds and all other “content”files from which you make your game。
  資源(Asset)是硬盤中的文件,存儲在Unity工程的Assets文件夾內。有些資源的數據格式是Unity原聲支持的,有些資源則需要轉換為源生的數據格式后才能被使用。
  對象(UnityEngine.Object),代表序列化數據的集合,表示某個資源的具體實例。它可以是Unity使用的任何類型的資源,所有對象都是UnityEngine.Object基類的子類
  資源與對象時一對多的關系。

名稱 描述 支持格式
Audio Clip 音頻剪輯 音頻:.aif .wav .mp3 .ogg音軌:.xm .mod .it .s3m
Cubemap Texture 立方體貼圖紋理
Flare 耀斑
Font 字體 .ttf
Material 材質
Meshes 網格 .FBX .dae .3DS .dxf .obj
Movie Texture 電影貼圖 .mov .mpg .mpeg .mp4 .avi .asf (導入需要QuickTime)
Procedural Material Assets 程序材質資源
Render Texture 渲染紋理
Text Asset 文本資源 .txt .html .htm .xml .bytes
Texture 2D 二維紋理 PSD TIFF JPG TGA PNG GIF BMP IFF PICT

除此之外,想使用Unity不支持導入,或者未經導入的資源,只能使用IO Stream或者WWW 方法,這些將在下文對應欄目中說明。
  注意:AssetBundle不是資源組件,故無法用資源組件的方式載入,只能使用WWW或者AssetBundle相關接口載入與讀取

GUID與fileID(本地ID)
  Unity會為每個導入到Assets目錄中的資源創建一個meta文件,文件中記錄了GUID,GUID用來記錄資源之間的引用關系。還有fileID(本地ID),用于標識資源內部的資源。資源間的依賴關系通過GUID來確定;資源內部的依賴關系使用fileID來確定。

InstanceID(實例ID)
  Unity為了在運行時,提升資源管理的效率,會在內部維護一個緩存表,負責將文件的GUID與fileID轉換成為整數數值,這個數值在本次會話中是唯一的,稱作實例ID(InstanceID)。
  程序啟動時,實例ID緩存與所有工程內建的對象(例如在場景中被引用),以及Resource文件夾下的所有對象,都會被一起初始化。如果在運行時導入了新的資源,或從AssetBundle中載入了新的對象,緩存會被更新,并為這些對象添加相應條目。實例ID僅在失效時才會被從緩存中移除,當提供了指定文件GUID和fileID的AssetBundle被卸載時會產生移除操作。
  卸載AssetBundle會使實例ID失效,實例ID與其文件GUID和fileID之間的映射會被刪除以便節省內存。重新載入AssetBundle后,載入的每個對象都會獲得新的實例ID。

** 資源的生命周期**
  Object從內存中加載或卸載的時間點是定義好的。Object有兩種加載方式:自動加載與外部加載。當對象的實例ID與對象本身解引用,對象當前未被加載到內存中,而且可以定位到對象的源數據,此時對象會被自動加載。對象也可以外部加載,通過在腳本中創建對象或者調用資源加載API來載入對象(例如:AssetBundle.LoadAsset)
對象加載后,Unity會嘗試修復任何可能存在的引用關系,通過將每個引用文件的GUID與FileID轉化成實例ID的方式。一旦對象的實例ID被解引用且滿足以下兩個標準時,對象會被強制加載:
  實例ID引用了一個沒有被加載的對象。
  實例ID在緩存中存在對應的有效GUID和本地ID。
  如果文件GUID和本地ID沒有實例ID,或一個已卸載對象的實例ID引用了非法的文件GUID和本地ID,則引用本身會被保留,但實例對象不會被加載。在Unity編輯器中表現為空引用,在運行的應用中,或場景視圖里,空對象會以多種方式表示,取決于丟失對象的類型:網格會變得不可見,紋理呈現為紫紅色等等。

** MonoScripts**
  一個MonoScripts含有三個字符串:程序庫名稱,類名稱,命名空間。
構建工程時,Unity會收集Assets文件夾中獨立的腳本文件并編譯他們,組成一個Mono程序庫。Unity會將Assets目錄中的語言分開編譯,Assets/Plugins目錄中的腳本同理。Plugin子目錄之外的C#腳本會放在Assembly-CSharp.dll中。而Plugin及其子目錄中的腳本則放置在Assembly-CSharp-firstpass.all中。
這些程序庫會被MonoScripts所引用,并在程序第一次啟動時被加載。

3、資源文件夾
** Assets**
  為Unity編輯器下的資源文件夾,Unity項目編輯時的所有資源都將置入此文件夾內。在編輯器下,可以使用以下方法獲得資源對象:
  AssetDatabase.LoadAssetAtPath("Assets/x.txt");
  注意:此方法只能在編輯器下使用,當項目打包后,在游戲內無法運作。參數為包含Assets內的文件全路徑,并且需要文件后綴。
  Assets下的資源除特殊文件夾內,或者在會打入包內的場景中引用的資源,其余資源不會被打入包中。

Resources
資源載入
  Assets下的特殊文件夾,此文件夾內的資源將會在項目打包時,全部打入包內,并能通過以下方法獲得對象:
  Resources.Load("fileName");
  Resources.Load("fileName");
  注意:函數內的參數為相對于Resource目錄下的文件路徑與名稱,不包含后綴。Assets目錄下可以擁有任意路徑及數量的Resources文件夾,在運行時,Resources下的文件路徑將被合并。
  例:Assets/Resources/test.txt與 Assets/TestFloder/Resources/test.png在使用Resource.Load("test")載入時,將被視為同一資源,只會返回第一個符合名稱的對象。如果使用Resource.Load(“test”)將返回text.txt;
  如果在Resources下有相同路徑及名稱的資源,使用以上方法只能獲得第一個符合查找條件的對象,使用以下方法能或得到所有符合條件的對象:
Object[] assets = Resources.LoadAll("fileName");
TextAsset[] assets = Resources.LoadAll("fileName");

** 相關機制**
  在工程進行打包后,Resource文件夾中的資源將進行加密與壓縮,打包后的程序內將不存在Resource文件夾,故無法通過路徑訪問以及更新資源。
  依本文2.3章節所述,在程序啟動時會為Resource下的所有對象進行初始化,構建實例ID。隨著Resource內資源的數量增加,此過程耗時的增加是非線性的。故會出現程序啟動時間過長的問題,請密切留意Resource內的資源數量。

卸載資源
  所有實例化后的GameObject 可以通過Destroy函數銷毀。請留意Object與GameObject之間的區別與聯系
Object可以通過Resources中的相關Api進行卸載

Resources.UnloadAsset(Object);//卸載對應Object 
Resources.UnloadUnusedAssets();//卸載所有沒有被引用以及實例化的Object 

注意以下情況:

Object obj = Resources.Load("MyPrefab"); 
GameObject instance = Instantiate(obj) as GameObjct; 
...... 
Destroy(instance); 
Resources.UnloadUnusedAssets(); 

此時UnloadUnusedAssets將不會生效,因為obj依然引用了MyPrefab,需要將obj = null,才可生效。


StreamingAssets
概述
  StreamingAssets文件夾為流媒體文件夾,此文件夾內的資源將不會經過壓縮與加密,原封不動的打包進游戲包內。在游戲安裝時,StreamAssets文件件內的資源將根據平臺,移動到對應的文件夾內。StreamingAssets文件夾在Android與IOS平臺上為只讀文件夾.
  你可以使用以下函數獲得不同平臺下的StreamingAssets文件夾路徑:

Application.streamingAssetsPath 

請參考以下各平臺下StreamingAssets文件夾的等價路徑,Application.dataPath為程序安裝路徑。Android平臺下的路徑比較特殊,請留意此路徑的前綴,在一些資源讀取的方法中是不必要的(AssetBundle.LoadFromFile,下詳)
Application.dataPath+"/StreamingAssets"http://Windows OR MacOS
Application.dataPath+"/Raw" //IOS
"jar:file://"+Application.dataPath+"!/assets/" //Android

文件讀取
  StreamingAssets文件夾下的文件在游戲中只能通過IO Stream或者WWW的方式讀取(AssetBundle除外)
IO Stream方式

using(FileStream stream = File.Open(Application.streamingAssetsPath + "fileName", FileMode.Open)) 
{ 
    //處理方法 
} 

WWW方式(注意協議與不同平臺下路徑的區別)

using(WWW www = new WWW(Application.streamingAssetsPath + "fileName")) 
{ 
    yield return www; 
    www.text; 
    www.texture; 
}

AssetBundle特有的同步讀取方式(注意安卓平臺下的路徑區別)

string assetbundlePath = 
#if UNITY_ANDROID 
Application.dataPath+"!/assets"; 
#else 
Application.streamingAssetsPath; 
#endif  
AssetBundle.LoadFromFile(assetbundlePath+"/name.unity3d"); 

PersistentDataPath

Application.persistentDataPath 

Unity指定的一個可讀寫的外部文件夾,該路徑因平臺及系統配置不同而不同。可以用來保存數據及文件。該目錄下的資源不會在打包時被打入包中,也不會自動被Unity導入及轉換。該文件夾只能通過IO Stream以及WWW的方式進行資源加載。

4、WWW載入資源
** 概述**
  WWW是一個Unity封裝的網絡下載模塊,支持Http以及file兩種URL協議,并會嘗試將資源轉換成Unity能使用的AssetsComponents(如果資源是Unity不支持的格式,則只能取出byte[])。具體對應的格式參考第一章表格。WWW加載是異步方法。

byte[] bytes = WWW.bytes; 
string text = WWW.text; 
Texture2D texture = WWW.texture; 
MovieTexture movie = WWW.movie; 
AssetBundle assetbundle = WWW.assetBundle; 
AudioClip audioClip = WWW.audioClip; 

相關機制
** new WWW**
  每次new WWW時,Unity都會啟用一個線程去進行下載。通過此方式讀取或者下載資源,會在內存中生成WebStream,WebStream為下載文件轉換后的內容,占用內存較大。使用WWW.Dispose將終止仍在加載過程中的進程,并釋放掉內存中的WebStream。
  如果WWW不及時釋放,將占用大量的內存,推薦搭配using方式使用,以下兩種方式等價。

WWW www = new WWW(Application.streamingAssetsPath + "fileName"); 
try 
{ 
    yield return www; 
    www.text; 
    www.texture; 
} 
finally 
{ 
    www.Dispose(); 
} 
using(WWW www = new WWW(Application.streamingAssetsPath + "fileName")) 
{ 
    yield return www; 
    www.text; 
    www.texture; 
} 

如果載入的為Assetbundle且進行過壓縮,則還會在內存中占用一份AssetBundle解壓用的緩沖區Deompresion Buffer,AssetBundle壓縮格式的不同會影響此區域的大小。

WWW.LoadFromCacheOrDownload

int version = 1; 
WWW.LoadFromCacheOrDownload(PathURL+"/fileName",version); 

使用此方式加載,將先從硬盤上的存儲區域查找是否有對應的資源,再驗證本地Version與傳入值之間的關系,如果傳入的Version>本地,則從傳入的URL地址下載資源,并緩存到硬盤,替換掉現有資源,如果傳入Version<=本地,則直接從本地讀取資源;如果本地沒有存儲資源,則下載資源。此方法的存儲路徑無法設定以及訪問。使用此方法載入資源,不會在內存中生成 WebStream(其實已經將WebStream保存在本地),如果硬盤空間不夠進行存儲,將自動使用new WWW方法加載,并在內存中生成WebStream。在本地存儲中,使用fileName作為標識符,所以更換URL地址而不更改文件名,將不會造成緩存資源的變更。
保存的路徑無法更改,也沒有接口去獲取此路徑

5、 AssetBundle
概述
  AssetBundles let you stream additional assets via the WWW class and instantiate them at runtime. AssetBundles are created via BuildPipeline.BuildAssetBundle.
  AssetBundle是Unity支持的一種文件儲存格式,也是Unity官方推薦的資源存儲與更新方式,它可以對資源(Asset)進行壓縮,分組打包,動態加載,以及實現熱更新,但是AssetBundle無法對Unity腳本進行熱更新,因為其需要在打包時進行編譯。

Assetbundle打包
平臺兼容性
  AssetBundle適用于多種平臺,但不同平臺所使用的AssetBundle并不相同,在創建AssetBundle時需要通過參數來指定目標平臺,其關系如下表

Standalone WebPlayer IOS Android
Standalone
WebPlayer
IOS
Android

創建API

public enum BuildAssetBundleOptions
{
    None = 0,
    //Build assetBundle without any special option. 
    UncompressedAssetBundle = 1,
    //Don't compress the data when creating the asset bundle. 
    CollectDependencies = 2,
    //Includes all dependencies. 
    CompleteAssets = 4,
    //Forces inclusion of the entire asset. 
    DisableWriteTypeTree = 8,
    //Do not include type information within the AssetBundle. 
    DeterministicAssetBundle = 16,
    //Builds an asset bundle using a hash for the id  
    ForceRebuildAssetBundle = 32,
    //Force rebuild the assetBundles. 
    IgnoreTypeTreeChanges = 64,
    //Ignore the type tree changes when doing the incremental build check. 
    AppendHashToAssetBundleName = 128,
    //Append the hash to the assetBundle name. 
    ChunkBasedCompression = 256
    //Use chunk-based LZ4 compression when creating the AssetBundle. 
}
AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles("OutputPath", BuildAssetBundleOptions, tragetPlatform);

在Unity的5.3版本中,簡化了AssetBundle的打包方式,只留下了一個api與寥寥幾個設置參數,而之前最讓人頭痛的資源依賴管理,也被默認進行處理。 而在每個Asset文件的Inspector面板上都會多出一個Asset Labels的設定欄:

AssetBundle name:需要將此資源打包的AssetBundle名稱
  AssetBundle Variant:需要將此資源打包的AssetBundle的變體名

Variant
  Variant是5.3以后新添加的一個概念,這個值其實是一個尾綴,將添加在對應AssetBundle的名稱之后,如:ddzgame.hd,hd就是Variant(從此以后AssetBundle的尾綴已經跟其文件類型本身沒有任何聯系)。

自動打包腳本
  從以上可知,如果需要一個一個的對資源設置AssetBundle Name與Variant實在太過繁瑣與麻煩,也可能出現紕漏,好在可以通過腳本去批量設置這兩個參數:

AssetImporter assetImporter = AssetImporter.GetAtPath("path");
assetImporter.assetBundleName = "Assetbundle Name";
assetImporter.assetBundleVariant = "Assetbundle Variant";

其中path是資源在Assets目錄下的路徑。

Scene打包
  Scene打包跟資源打包無異,唯一需要注意的是:Scene只能與Scene打入同一個AssetBundle內,而無法與其他資源打入同一個AssetBundle。
  PS:AssetBundle內的Scene需要在AssetBundle加載后,通過SceneManager來加載。

AssetBundle依賴
依賴機制
  假設有AssetBundleA與 AssetBundleB兩個AssetBundle,AssetBundle中的資源引用了AssetBundleB中的資源,則稱AssetBundleA依賴于AssetBundleB。具體實例請看下圖注意被依賴AssetBundle需要加載的時機

注意其依賴的機制: AssetBundle中保存有其中所有資源的GUID,FileID等序列化信息,AssetBundle只會在內存中尋找其依賴資源所在的AssetBundle,并自動從中加載出所需資源。具體可參考本文2.3章節

** Manifest**

在前面有提到,在5.3中,Unity會自動處理AssetBundle中資源的依賴關系。在默認情況下,如果AssetBundle間有交叉的資源引用,不會再重復打包,在打包AssetBundle后,會發現其在輸出目錄多出了一個與目錄名稱相同的無后綴AssetBundle文件,其為自動生成的AssetBundleManifest文件,其內保存有此次生成的所有AssetBundle之間的依賴關系與清單。我們可以在載入這個AssetBundle后使用以下方法獲得此對象。

AssetBundle.LoadAsset("AssetBundleManifest");

Manifest保存有重要的依賴信息,在載入AssetBundle時,可以通過Manifest查詢其是否有依賴的AssetBundle,然后我們手動對其進行管理,避免依賴項丟失而出現bug
string[] fullnames = AssetBundle.GetDirectDependencies(fullname);
string[] fullnames = AssetBundle.GetAllDependencies(fullname);
  Direct方法會返回所有直接依賴的AssetBundle名稱數組,All方法會返回所有依賴的AssetBundle名稱數組,fullname包括名稱與Variant。推薦使用Direct方法做遞歸處理,避免重復載入。

AssetBundle加載
加載方式
  之前已經提及,不再詳細說明,使用WWW 或者 AssetBundle相關API加載,其中AssetBundle的API只能進行本地加載。

AssetBundle.LoadfromMemory(byte[] bytes)

此API是一個例外,用來對加密的Assetbundle進行讀取,可以結合WWW使用。

壓縮
  LZMA(Ziv-Markov chain algorithm)格式
  Unity打包成AssetBundle時的默認格式,會將序列化數據壓縮成LZMA流,使用時需要整體解包。優點是打包后體積小,缺點是解包時間長,且占用內存。

LZ4格式
  5.3新版本添加的壓縮格式,壓縮率不及LZMA,但是不需要整體解壓。LZ4是基于chunk的算法,加載對象時只有響應的chunk會被解壓。
  壓縮格式在打包時通過AssetBundleOption參數選擇。

內存占用

AssetBundle加載后會在內存中生成AssetBundle的序列化架構的占用,一般來說遠遠小于資源本身,除非包含復雜的序列化信息(復雜多層級關系或復雜靜態數據的prefab等)


AssetBundle卸載
卸載API

AssetBundle.Unload(bool unloadAllLoadedObjects);

AssetBundle只有唯一的一個卸載函數,傳入的參數用來選擇是否將已經從此AssetBundle中加載的資源一起卸載。另外,已經從AssetBundle中加載的資源可以通過Resources.UnloadAsset(Object)卸載。如果想通過Resources.UnloadUnusedAssets()卸載從AssetBundle加載的資源,一定要先將AssetBundle卸載后才能生效。

資源卸載總覽

內存關系圖

當AssetBundle被卸載后,實例ID與其文件GUID和本地ID之間的映射會被刪除, 即其無法被其后加載的依賴于它的資源所查找及引用。詳情請參考本文2.3章節

** 案例分析**
  案例1 游戲切換到后臺一段時候切回,出現shader或者Texture丟失。
  在移動平臺,當程序切到主界面或者在后臺長時間運行時,GPU會自動對后臺程序的資源進行清理。如果shader或者Texture是從AssetBundle中加載出來,而此AssetBundle已經被卸載的話,Unity無法在程序恢復時從內存中加載這些資源,從而造成丟失。有人會問,這些資源不是已經加載到內存中了么?但是,他們在被加載到GPU之后會被從內存中清除。因此要防止此狀況最穩健的方法,就是在場景切換前,不要卸載掉其所屬的AssetBundle。
  案例2 當經常使用AssetBundleB.Unload(false)卸載時,有時會發現AssetBundle中的資源在內存中有多份同時存在。
  問題的根源在于從AssetBundle中加載出來的資源,在該AssetBundle卸載之后與其的聯系就斷開了。

例如:從AssetBundleA中加載出來一個Prefab p1,p1依賴資源tex1也會自動加載到內存中。然后用AssetBundle.Unload(false)卸載AssetBundleA,此時p1與AssetBundleA的聯系斷開。之后,從AssetBundleA中加載Prefab p2,p2也依賴資源tex1,那么在加載p2時tex1會再次被加載到內存中,導致重復。

原文地址:http://gad.qq.com/article/detail/7180936
作者:Loki+X

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 翻譯:莫銘原文地址:AssetBundle usage patterns 本系列中的上一篇文章覆蓋了AssetBu...
    莫銘閱讀 5,309評論 1 12
  • 這部分主要討論了AssetBundle的如下知識: AssetBundle的基礎知識 使用AssetBundle的...
    Wenchao閱讀 1,626評論 0 5
  • 這一部分主要是對Unity的Resources系統和AssetBundle系統進行深入討論。 分為四個部分: 有關...
    Wenchao閱讀 2,021評論 0 1
  • 1、什么是AssetBundle AssetBundle 是Unity pro提供的一種用來存儲資源的文件格式,它...
    好怕怕閱讀 7,577評論 1 8
  • 我只想做個夜半的歌者, 夜色里流淌出款款深情。 溫潤的風, 染十指rou情,把月光彈破, 碎成了星空, 青春而悄皮...
    天山木蘭閱讀 189評論 0 0