07-01.Resource和AssetBundle教程

這一部分主要是對Unity的Resources系統(tǒng)和AssetBundle系統(tǒng)進(jìn)行深入討論酪耳。

分為四個部分:

  1. 有關(guān)Asset的底層細(xì)節(jié)畅买,Asset序列化和引用之間的關(guān)系熄赡;

  2. Resources系統(tǒng)

  3. AssetBundle 基礎(chǔ)

  4. AssetBundle 實(shí)踐

這篇文章主要是第一部分:

Assets, Objects 和 序列化操作

要點(diǎn):

  • Asset和UnityEngine.Object的區(qū)別和聯(lián)系
  • 實(shí)例ID(instance ID)
  • 序列化和實(shí)例化
  • MonoScript腳本
  • 資源生命周期
  • 復(fù)雜層次的Prefab的導(dǎo)入和優(yōu)化

Asset和Object

Asset指的是存儲在磁盤上的資產(chǎn)文件,在Unity工程下的Assets目錄下的所有文件都可以認(rèn)為是Asset盐类。如材質(zhì)、紋理和FBX模型呛谜,這些都可以認(rèn)為是Asset傲醉。

Asset包括兩種,一種是使用Unity工具創(chuàng)建的呻率,例如材質(zhì)這些硬毕;另外一種則是從外部導(dǎo)入的文件,Unity轉(zhuǎn)換成為自己可以使用的格式礼仗,如FBX文件吐咳。

而Object,一般指的是繼承UnityEngine.Object類的所有實(shí)例元践。Object指的是某個資源的特定實(shí)例韭脊,里面包含著序列化的數(shù)據(jù)。Object可以是Unity引擎使用到的任何資源形式单旁,如網(wǎng)格沪羔、音頻片段、動畫片段等等。

兩個需要特別注意的Object類:

  1. ScriptableObject給開發(fā)者提供了自定義數(shù)據(jù)類型的方法蔫饰。繼承ScriptableObject的類型可以被Unity序列化和反序列化琅豆,而且可以在編輯器中的Inspector窗口中查看。

  2. MonoBehaviour提供了鏈接到MonoScript的包裝類篓吁。MonoScript是Unity用來持有某個特定腳本類的引用的數(shù)據(jù)類型茫因。MonoScript不包含任何實(shí)際的執(zhí)行代碼。

Asset和Object的關(guān)系是一對多的杖剪,一個Asset文件里面可以包含一個或者多個Object冻押。

Object之間的引用關(guān)系

Object之間可以互相引用。一個Object既可以引用存在于同一個Asset文件中的Object盛嘿,也可以引用存在于其他Asset文件中的Object洛巢。例如,材質(zhì)Object就可以引用多個紋理Object次兆,這些紋理Object可以存在于一個紋理Asset文件中稿茉,也可以存在于多個紋理Asset文件中。

那么类垦,Unity是如何存儲這些引用的呢狈邑?

當(dāng)被序列化的時(shí)候,這些引用會使用兩份獨(dú)立的數(shù)據(jù)進(jìn)行存儲:文件GUID(File GUID)和局部ID(local ID)蚤认。

文件GUID用來標(biāo)記Asset文件的具體位置米苹。

局部ID則用來標(biāo)記Asset文件中的Object,局部ID不會重復(fù)砰琢,一個Asset文件中不同的Object的局部ID也會唯一蘸嘶。

文件GUID存在于.meta文件中,這些.meta文件會在Asset文件第一次被導(dǎo)入U(xiǎn)nity的時(shí)候生成陪汽,存在和Asset文件相同的文件夾內(nèi)训唱。

這些信息是可以通過文本編輯器查看,將Unity工程的Editor Setting設(shè)置成expose Visible Meta Fileto serialize Assets as Text挚冤。

新創(chuàng)建一個材質(zhì)文件况增,同時(shí)向工程中導(dǎo)入一個紋理文件,將材質(zhì)賦給場景中的立方體并且儲存這個場景训挡。

使用文本編輯器打開材質(zhì)文件對應(yīng)的.meta文件:

fileFormatVersion: 2
guid: b2f39b876f4ffe247b63e00b09aea5cd
...... 

文件開頭出現(xiàn)的guid標(biāo)簽定義的就是材質(zhì)文件的GUID澳骤。

如果想要看到局部ID,使用文本編輯器打開材質(zhì)文件澜薄,可以看到類似于下面的信息:

--- !u!21 &2100000
Material:
 serializedVersion: 3
 ... more data ...

在上面的例子中为肮,&后面跟著的就是材質(zhì)的局部ID。如果材質(zhì)文件的.meta文件中的guidabcdefg的話肤京,那么使用文件GUID abcdefg和局部ID 2100000唯一確定了颊艳。

為什么同時(shí)采用文件GUID和局部ID?

簡單來講,是為了更強(qiáng)的健壯性和獨(dú)立于平臺的設(shè)計(jì)方法棋枕。

文件GUID提供了文件存儲位置的抽象白修,因?yàn)椴煌奈募腉UID不同,所以根據(jù)GUID就可以找到文件戒悠,文件的實(shí)際存儲位置就變得無關(guān)緊要了熬荆。這個文件可以自由移動舟山,而不需要去更新所以引用到這個文件的其他文件的信息绸狐。

而任何Asset文件都可以包含多個Object,使用局部ID就可以對這些Object進(jìn)行區(qū)分累盗。

如果Asset文件關(guān)聯(lián)的文件GUID丟失寒矿,那么對這個Asset里面的Object的所有引用也會全部失效。這就是.meta為什么要存放在Asset文件的同一個文件夾下面若债,而且名字也要和Asset的名稱一樣符相。注意,Unity會重新生成誤刪或者放錯位置的.meta文件蠢琳。同樣啊终,當(dāng)Asset文件已經(jīng)不存在的時(shí)候,Unity也會刪除掉多余的.meta文件

Unity編輯器會維護(hù)一個所有文件的路徑和文件GUID之間對應(yīng)關(guān)系的映射表傲须。當(dāng)新的Asset被導(dǎo)入的時(shí)候蓝牲,映射表會記錄下GUID和文件路徑之間的關(guān)系。如果Unity打開的時(shí)候泰讽,.meta文件丟失例衍,而Asset的路徑?jīng)]有發(fā)生變化,Unity可以確保生成一樣的GUID已卸。

當(dāng)Unity編輯器關(guān)閉的時(shí)候佛玄,改變Asset文件的路徑,而且沒有移動對應(yīng)的.meta文件累澡,那么對這個Asset文件中的Object的引用會失效梦抢。

復(fù)合Asset文件的導(dǎo)入

所有不是Unity創(chuàng)建的資源都需要導(dǎo)入的流程才能被Unity使用,Unity導(dǎo)入的流程是自動發(fā)生的愧哟,但是可以通過腳本對導(dǎo)入的過程進(jìn)行自定義奥吩。AssetImporter和相關(guān)的子類就可以完成這些工作,例如TextureImporter的API就可以完成導(dǎo)入紋理資源翅雏,如PNG圖片或者JPG圖片的時(shí)候可以執(zhí)行的操作圈驼。

導(dǎo)入結(jié)果就是一個Asset文件中可能會包含一個或者多個Object。這些都是可以通過Unity編輯器的Inspector窗口查看望几。例如绩脆,當(dāng)一個紋理資源包含多個子Sprite時(shí)候,所有的子Sprite都會共享同一個GUID,而根據(jù)局部ID進(jìn)行區(qū)分靴迫。

導(dǎo)入流程需要將原始的Asset文件轉(zhuǎn)換成為目標(biāo)平臺適用的資源類型惕味,可能會執(zhí)行一些比較復(fù)雜的操作,比如紋理壓縮玉锌。試想一下名挥,如果每次打開Unity都需要重復(fù)執(zhí)行這些操作,需要耗費(fèi)很多時(shí)間主守。

所以禀倔,Unity采用的解決辦法是,將Asset文件導(dǎo)入的結(jié)果緩存在Library中参淫。需要指出的是救湖,導(dǎo)入的最終結(jié)果會放在Asset文件GUID前兩位數(shù)字命名的文件夾中,這些文件夾放在Library/metadata文件夾中涎才。這些導(dǎo)入產(chǎn)生的Object會被序列化成一個和Asset文件GUID一樣的二進(jìn)制文件鞋既。

雖然所有的Asset都是這樣處理,但是原生的Asset不需要轉(zhuǎn)換和反序列化操作耍铜。

序列化和實(shí)例化

雖然文件GUID和局部ID這種設(shè)計(jì)方法能夠保證穩(wěn)定性邑闺,但是另一方面,這樣的設(shè)計(jì)也會導(dǎo)致性能問題棕兼,所以需要在運(yùn)行時(shí)能夠支撐性能陡舅。所以Unity內(nèi)部會維護(hù)一個緩存【在底層,這個緩存用PersistentManager來管理程储。內(nèi)部的轉(zhuǎn)換過程是通過Unity的C++的Remapper完成的蹭沛,Remapper沒有通過任何API暴露】,這個緩存會將文件GUID和局部ID轉(zhuǎn)換成一個整數(shù)章鲤,并且保證在某次運(yùn)行過程中唯一摊灭。這些整數(shù)被稱為實(shí)例ID(instance ID),使用簡單的自增順序管理败徊,當(dāng)新Object在管理器中被注冊的時(shí)候帚呼,便把當(dāng)前的實(shí)例ID賦給Object,同時(shí)自增加1.

緩存管理器會維護(hù)一個實(shí)例ID和存放在內(nèi)存中的Object之間的映射關(guān)系皱蹦,這樣同時(shí)也能夠保證Object之間存在穩(wěn)定的引用關(guān)系煤杀。對一個實(shí)例ID進(jìn)行解析就可以找到已經(jīng)加載的Object,如果對應(yīng)的目標(biāo)Object沒有被加載沪哺,那么根據(jù)文件GUID和局部ID也可以找到Object對應(yīng)的Asset文件沈自,從存儲器中加載。

在啟動階段辜妓,Project場景中引用到的所有Object以及所有Resources目錄下的Object的Instance ID緩存都會被初始化枯途。在運(yùn)行過程中忌怎,如果從AssetBundle中加載進(jìn)來創(chuàng)建新的Object,緩存中也會加入新的信息酪夷。當(dāng)Object失效的時(shí)候榴啸,緩存中的信息也會被清除掉。當(dāng)AssetBundle被卸載的時(shí)候晚岭,有可能會發(fā)生這些過程鸥印。

關(guān)于更多的AssetBundle的信息,可以參見
AssetBundle Usage Pattern

需要特別指出的是坦报,某些特定平臺的某些事件可以強(qiáng)行從內(nèi)存中移除Object库说。例如,在iOS設(shè)備上燎竖,當(dāng)應(yīng)用被掛起的時(shí)候璃弄,圖形顯示相關(guān)的Asset會從顯卡內(nèi)存中移除要销。如果這些Object的源文件AssetBundle被卸載构回,Unity就不能重新載入這些Object的源數(shù)據(jù)了。關(guān)于這些Object現(xiàn)有的引用也會無效疏咐。上面的例子可能會導(dǎo)致出現(xiàn)網(wǎng)格丟失或者模型的紋理或材質(zhì)丟失的問題纤掸。

具體的實(shí)現(xiàn)細(xì)節(jié)可能比上面描述的情況更加復(fù)雜。在執(zhí)行很大的加載操作的時(shí)候浑塞,頻繁比較文件GUID和局部ID并不是非常劃算的操作借跪。當(dāng)打包的時(shí)候,文件GUID和局部ID會建立一個簡單的映射關(guān)系酌壕。盡管如此掏愁,上面描述的流程還是大致符合的,只需要記住文件GUID和局部ID在運(yùn)行的時(shí)候是獨(dú)一無二的卵牍。

還有果港,在運(yùn)行階段,Asset文件的GUID也是不可以被查詢糊昙。

MonoScript腳本

MonoBehaviour對象會引用到MonoScript對象辛掠,MonoScript對象包含著定位到某個特定腳本對象的信息,但是這兩個對象都不會包括腳本類執(zhí)行的具體方法释牺。

每個MonoScript包含三個字符串信息:程序集名稱萝衩,類名和命名空間

每當(dāng)打包一個工程的時(shí)候没咙,Unity會收集Assets下所有腳本文件猩谊,并將這些文件編譯成Mono程序集。Unity會對Assets下不同語言編寫的代碼進(jìn)行區(qū)分祭刚,分開編譯成不同的程序集牌捷。而且Assets/Plugins目錄下的代碼也會被單獨(dú)處理队塘。Plugins子目錄外的代碼被放入Assembly-CSharp.dll中。Plugins目錄內(nèi)的代碼被放入到Assembly-CSharp-firstpass.dll中宜鸯。

這些程序集(加上提前編譯好的程序集DLL)都會被打進(jìn)最后的Unity應(yīng)用中憔古。MonoScript也會引用到這些程序集。不同于其他的資源類型淋袖,Unity應(yīng)用中的所有程序集會在一開始就被加載進(jìn)來鸿市。

AssetBundle的MonoBehaviour組件上并沒有包含真正可執(zhí)行的代碼,是因?yàn)槭褂昧薓onoScript的原因即碗。而且這樣也能夠保證允許不同的MonoBehaviour可以引用共享的類焰情,即使MonoBehaviour是存在于不同的AssetBundle中。

資源的生命周期

UnityEngine.Object對象可以在指定的時(shí)間被加載進(jìn)內(nèi)存或者從內(nèi)存中卸載剥懒。為了減少加載時(shí)間和管理應(yīng)用內(nèi)存内舟,所以需要掌握Object資源的生命周期。

有兩種加載Object的方法:自動加載和顯示調(diào)用加載初橘。

自動加載:當(dāng)Instance ID被引用的時(shí)候验游,Object并沒有存在內(nèi)存中,而且Object對應(yīng)的Asset文件可以被定位到的時(shí)候保檐,Object就會被自動加載耕蝉。

顯示調(diào)用加載:通過調(diào)用資源加載相關(guān)的API(如AssetBundle.LoadAsset)。

當(dāng)Object被加載的時(shí)候夜只,Unity會嘗試解析所有的引用關(guān)系垒在,并將這些引用到的文件GUID和局部ID轉(zhuǎn)換成Instance ID。

如果Instance ID被間接引用到的時(shí)候扔亥,而且滿足如下的兩個條件场躯,那么Object就會立馬被加載進(jìn)來:

  1. Instance ID對應(yīng)的Object還沒有被加載進(jìn)內(nèi)存。
  2. Instance ID在緩存中注冊的文件GUID和局部ID已經(jīng)失效旅挤。

這個通常當(dāng)被引用之后很快就被執(zhí)行踢关。

如果一個文件GUID和局部ID并沒有Instance ID,或者某個已經(jīng)卸載掉的Object的Instance ID引用著一個無效的文件GUID和局部ID谦铃。這個引用繼續(xù)唄把持耘成,但是Object不會被加載。當(dāng)出現(xiàn)這種情況的時(shí)候驹闰,Unity編輯器中就會出現(xiàn)丟失的引用瘪菌,在場景視圖中,不同類型的丟失Object的表現(xiàn)形式也各不相同:網(wǎng)格會不可見嘹朗,而紋理貼圖則會變成洋紅色师妙。

Object通常會在如下的情況下被卸載:

  1. 當(dāng)未被使用的Asset被清除的時(shí)候,關(guān)聯(lián)的Object也會被卸載屹培。當(dāng)場景會強(qiáng)制卸載的時(shí)候默穴,就會出現(xiàn)這種情況怔檩,例如調(diào)用Application.LoadLevel或者Resources.UnloadUnusedAssets。這個過程只會卸載掉沒有被引用的Object蓄诽,沒有引用指的是沒有任何Mono變量持有這個Object的引用薛训,場景中的其他活動狀態(tài)下的Object也沒有持有該Object的引用。

  2. 來自于Resources目錄中的Object可以通過調(diào)用Resources.UnloadAsset顯式卸載仑氛。這些Object的Instance ID仍然有效乙埃,而且緩存中的文件GUID和局部ID也仍然有效。如果Mono變量或者其他的Object再次持有已經(jīng)被Resources.UnloadAsset卸載掉的Object的引用的時(shí)候锯岖,被卸載掉的Object也會被再次加載進(jìn)來介袜。

  3. 來自于AssetBundle的Object的話,當(dāng)調(diào)用AssetBundle.Unload(true)的時(shí)候出吹,會卸載掉Object遇伞,這樣會讓Object的Instance ID對應(yīng)的文件GUID和局部ID都會失效,而且所有關(guān)于被卸載的Object的引用都會變成丟失狀態(tài)捶牢。對于C#腳本而言鸠珠,任何嘗試獲取已經(jīng)被卸載掉的Object中的方法或者屬性都會產(chǎn)生NullReferenceException的報(bào)錯信息。

如果調(diào)用的是AssetBundle.Unload(false)叫确,那么從這個AssetBundle中的正在處于活躍狀態(tài)下的Object不會被卸載跳芳,但是Unity會讓文件GUID和局部ID都失效,如果這些內(nèi)存中的Object被移除的話竹勉,Unity就不能重新加載這些Object,而且對這些Object的引用仍然保持著娄琉。

導(dǎo)入有著復(fù)雜層次的Prefab

當(dāng)序列化有著復(fù)雜層次的GameObject的時(shí)候次乓,需要記住,整個層次結(jié)構(gòu)是一起被序列化的孽水。層次中的每一個GameObject和組件在序列化中的數(shù)據(jù)都是獨(dú)立的票腰。這對于加載和實(shí)例化這些GameObject的時(shí)間有著巨大影響。

當(dāng)創(chuàng)建一個新的具有復(fù)雜層次的GameObject時(shí)女气,主要的CPU消耗來自于如下地方:

  • 讀取GameObject的數(shù)據(jù)(從磁盤加載杏慰,或者從內(nèi)存中已經(jīng)存在的GameObject)
  • 建立新的Transform之間的父子層級關(guān)系
  • 實(shí)例化新的GameObject和對應(yīng)的組件
  • 調(diào)用GameObject和組件中的Awake方法

后面的三個步驟消耗的時(shí)間,對于GameObject是從磁盤中讀取數(shù)據(jù)還是從內(nèi)存中讀數(shù)據(jù)而言差別不大炼鞠。但是對于第一個步驟而言缘滥,既和從加載的數(shù)據(jù)源頭有關(guān),也和層次中的GameObject和組件的數(shù)目相關(guān)谒主。

在目前的情況下朝扼,從內(nèi)存中讀取數(shù)據(jù)肯定快于從磁盤中讀取數(shù)據(jù),而且不同平臺的差異也會非常大霎肯。桌面PC的速度通城嬗保快于移動設(shè)備榛斯。

所以,如果在存儲器讀取速度比較慢的設(shè)備上加載Prefab的時(shí)候搂捧,花在存儲器讀取序列化數(shù)據(jù)的時(shí)間遠(yuǎn)遠(yuǎn)超過實(shí)例化Prefab的時(shí)間驮俗,所以主要的消耗時(shí)間就是就存儲器I/O決定的。

還有允跑,當(dāng)序列化一個巨大的Prefab的時(shí)候意述,其中的每個GameObject和組件都是分來序列化的——即使里面有很多的數(shù)據(jù)是重復(fù)的。如果一個UI包括30個一樣的元素吮蛹,那么這個元素同樣會被序列化30次荤崇,一方面會導(dǎo)致序列化之后的文件很大,另一方面這樣也讓讀取慢了很多潮针。

采取的優(yōu)化方法是术荤,將重復(fù)的元素拆分成獨(dú)立的Prefab,在運(yùn)行時(shí)實(shí)例化這些重用的元素每篷,而不是將它們放到同一個Prefab中瓣戚,依靠Unity的序列化系統(tǒng)去處理他們。這樣優(yōu)化的話焦读,可能會節(jié)約不少時(shí)間子库。

另外,從場景中已經(jīng)存在的GameObject復(fù)制所花的時(shí)間會遠(yuǎn)遠(yuǎn)少于從存儲器中加載一個新的Prefab矗晃。

Unity 5.4 提示:從Unity5.4版本開始仑嗅,transform在內(nèi)存中的存儲方式進(jìn)行了修改,每個根節(jié)點(diǎn)的Transofrm和子節(jié)點(diǎn)的Transform信息在內(nèi)存中是連續(xù)儲存的张症。所以當(dāng)實(shí)例化新的GameObject仓技,并且需要馬上改變GameObject的層次的時(shí)候,最好使用帶有parent參數(shù)的Game.Instantiate的方法俗他。

參考:https://docs.unity3d.com/ScriptReference/Object.Instantiate.html

使用新的API可以避免對新的GameObject根節(jié)點(diǎn)Transform的內(nèi)存分配脖捻。在測試情況下,使用這個API通常會快5%~10%兆衅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末地沮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子羡亩,更是在濱河造成了極大的恐慌摩疑,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夕春,死亡現(xiàn)場離奇詭異未荒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)及志,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門片排,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寨腔,“玉大人,你說我怎么就攤上這事率寡∑嚷” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵冶共,是天一觀的道長乾蛤。 經(jīng)常有香客問我,道長捅僵,這世上最難降的妖魔是什么家卖? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮庙楚,結(jié)果婚禮上上荡,老公的妹妹穿的比我還像新娘。我一直安慰自己馒闷,他們只是感情好酪捡,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纳账,像睡著了一般逛薇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疏虫,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天永罚,我揣著相機(jī)與錄音,去河邊找鬼议薪。 笑死尤蛮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斯议。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼醇锚,長吁一口氣:“原來是場噩夢啊……” “哼哼御!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起焊唬,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤恋昼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赶促,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體液肌,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年鸥滨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗦哆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谤祖。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖老速,靈堂內(nèi)的尸體忽然破棺而出粥喜,到底是詐尸還是另有隱情,我是刑警寧澤橘券,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布额湘,位于F島的核電站,受9級特大地震影響旁舰,放射性物質(zhì)發(fā)生泄漏锋华。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一箭窜、第九天 我趴在偏房一處隱蔽的房頂上張望毯焕。 院中可真熱鬧,春花似錦绽快、人聲如沸芥丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽续担。三九已至,卻和暖如春活孩,著一層夾襖步出監(jiān)牢的瞬間物遇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工憾儒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留询兴,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓起趾,卻偏偏與公主長得像诗舰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子训裆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 這部分主要討論了AssetBundle的如下知識: AssetBundle的基礎(chǔ)知識 使用AssetBundle的...
    Wenchao閱讀 1,598評論 0 5
  • 翻譯:莫銘原文地址:AssetBundle usage patterns 本系列中的上一篇文章覆蓋了AssetBu...
    莫銘閱讀 5,235評論 1 12
  • 原文地址:http://gad.qq.com/article/detail/7180936作者:Loki+XUni...
    重裝機(jī)霸閱讀 8,189評論 0 41
  • 十月就快過完了眶根,抓不住時(shí)間的尾巴 Banner設(shè)計(jì)可以說是我日常工作中最主要的一塊需求,banner不比大型項(xiàng)目边琉,...
    琳purple閱讀 337評論 0 0
  • 昨晚我睡在濤濤的洪水中 迅猛属百、沉重 拖著皮沓的身子像一塊腐木 我和我整個的生活一起 被水流淘洗 越洗越洗不清 轟鳴...
    葉虛愚閱讀 240評論 0 6