本文介紹了 Unity 常用四種默認(rèn)路徑,以及 AssetDataBase、Resources灾锯、AssetBundle 和目前最新的 Addressable 四種資源管理方式
文中所有 API 均以版本 2019.3 為準(zhǔn)
本文原地址:Unity學(xué)習(xí)—資源管理概覽
資源路徑
Application.dataPath
只讀猾愿,Editor 可讀寫(xiě)
游戲數(shù)據(jù)相對(duì)路徑,即游戲安裝路徑若债,PC 上路徑會(huì)使用 '/' 分割文件夾
-
Unity Editor:
<項(xiàng)目根路徑>/Assets
-
Mac player:
<App 包路徑>/Contents
-
iOS player:
<App 包路徑>/<AppName.app>/Data
-
Win/Linux player:
<可執(zhí)行數(shù)據(jù)文件夾路徑>
- WebGL: player data 文件的 絕對(duì) url 地址 (不包含具體文件名)
- Android: 一般為 APK 路徑, 若使用 split binary build, 則為 OBB 路徑
- Windows Store Apps: player data 文件夾的絕對(duì)地址
Application.persistentDataPath
可讀寫(xiě)拆融,用于持久化數(shù)據(jù)存儲(chǔ)蠢琳,在 iOS 和 Android 平臺(tái)該路徑指向設(shè)備的公共路徑,該目錄不會(huì)隨 App 升級(jí)而刪除镜豹,但可被用戶(hù)直接刪除
persistentDataPath
的路徑由Bundle Identifier
生成的 GUID 組成傲须,只要Bundle Identifier
不變,路徑不變
iOS 會(huì)自動(dòng)將 persistentDataPath 路徑下的文件備份到 iCloud
-
Windows Store Apps:
%userprofile%\AppData\Local\Packages\<productname>\LocalState
-
iOS:
/var/mobile/Containers/Data/Application/<guid>/Documents
-
Android:
/storage/emulated/0/Android/data/<packagename>/files
該路徑由 android.content.Context.getExternalFilesDir 獲得趟脂,部分機(jī)型該路徑會(huì)指向 SD 卡 -
Mac:
~/Library/Application Support/<company name>/<product name>
泰讽,舊版本還可能為~/Library/Caches
或~/Library/Application Support/unity.company name.product name
,Unity 會(huì)查詢(xún)并使用以上路徑中最早的路徑
Application.streamingAssetsPath
只讀,Editor 可讀寫(xiě)
流數(shù)據(jù)存儲(chǔ)的相對(duì)路徑已卸,該目錄下 Asset 在 Unity 編譯時(shí)不會(huì)被 Unity 打包佛玄,使其在運(yùn)行時(shí)可直接通過(guò)路徑獲取,可將資源放入 Assets 目錄下任何名為 StreamingAssets
文件夾
StreamingAssets
中資源可使用 I/O 讀取累澡,但 WebGL 和 Android 平臺(tái)下該路徑為 URL梦抢,不支持直接獲取,因此需使用 UnityWebRequest
獲取愧哟。若其他平臺(tái)使用 UnityWebRequest
獲取奥吩,則需在路徑前加上"file://"
,如 "file://" + Application.streamingAssetsPath + "/file.mp4"
-
Unity Editor, Windows, Linux players, PS4, Xbox One, Switch :
Application.dataPath + "/StreamingAssets"
-
Mac:
Application.dataPath + "/Resources/Data/StreamingAssets"
-
iOS:
Application.dataPath + "/Raw"
-
Android:
"jar:file://" + Application.dataPath + "!/assets"
(壓縮后的 APK/JAR 文件)
Application.temporaryCachePath
可讀寫(xiě)翅雏,臨時(shí)數(shù)據(jù)和緩存路徑圈驼,應(yīng)用更新或覆蓋安裝時(shí)不會(huì)被清除,手機(jī)空間不足時(shí)才可能會(huì)被系統(tǒng)清除
路徑示例
路徑 | Editor | Windows | Mac OS | iOS | Android |
---|---|---|---|---|---|
Application.dataPath | 項(xiàng)目路徑/Assets | 安裝路徑/ProductName_Data | /Applications/AppName.app/Contents | /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AppName.app/Data | /data/app/package.name.apk |
Application.persistentDataPath | C:/Users/username/AppData/LocalLow/CompanyName/ProductName <br />或<br />/Users/username/Library/Application Support/CompanyName/ProductName | C:\Users\username\AppData\LocalLow\CompanyName\ProductName | /Users/username/Library/Application Support/CompanyName/AppName | /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents | /data/data/package.name/files |
Application.streamingAssetsPath | 項(xiàng)目路徑/Assets/StreamingAssets | 安裝路徑/ProductName_Data/StreamingAssets | /Applications/AppName.app/Contents/Resources/Data/StreamingAssets | /var/containers/Bundle/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AppName.app/Data/Raw | jar:file:///data/app/package.name.apk/!/assets |
Application.temporaryCachePath | C:/Users/username/AppData/Local/Temp/CompanyName/ProductName<br />或<br />/var/folders/xx/xxxxxxxxxxxxxx/X/CompanyName/ProductName | C:\Users\username\AppData\Local\Temp\CompanyName\ProductName | /var/folders/xx/xxxxxxxxxxxxxx/X/CompanyName/ProductName | /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches | /data/data/package.name/cache |
讀寫(xiě)權(quán)限說(shuō)明
https://blog.csdn.net/BillCYJ/article/details/99712313
資源加載
AssetDataBase
AssetDataBase 可在 Editor 環(huán)境下對(duì)項(xiàng)目 Asset 進(jìn)行增刪改查等操作(可實(shí)現(xiàn)與 Unity 編輯器頂部工具欄 Assets 選項(xiàng)下基本相同的功能)望几,使用方法可參考官方手冊(cè) 接口文檔
Resources
可在項(xiàng)目 Assets 目錄下任意位置創(chuàng)建Resources
文件夾绩脆,打包時(shí) Unity 會(huì)整合所有位于Resources
文件夾的 Asset 及其依賴(lài),并生成一個(gè)只讀的 resources.assets
資產(chǎn)文件橄抹,對(duì)于 Resources 目錄中在游戲中被直接引用的資產(chǎn)靴迫,則會(huì)被另外打包到 sharedassets0.assets
中
Resources 最佳實(shí)踐
官方的建議是不使用 Resources,有以下幾點(diǎn)原因:
- Resources 文件夾會(huì)導(dǎo)致內(nèi)存管理困難
- 不適當(dāng)使用 Resources 文件夾會(huì)加長(zhǎng)應(yīng)用啟動(dòng)和編譯時(shí)間楼誓,Resources 文件夾越多玉锌,Asset 管理越困難
- Resources 系統(tǒng)降低項(xiàng)目針對(duì)指定平臺(tái)使用自定義內(nèi)容的能力,并且無(wú)法實(shí)現(xiàn)增量更新(AssetBundle 是 Unity 針對(duì)不同設(shè)備提供特定內(nèi)容的主要工具)
適合使用 Resources 的場(chǎng)景:
- 因其簡(jiǎn)單快速的特性疟羹,適合用于快速原型和實(shí)驗(yàn)開(kāi)發(fā)主守,但當(dāng)正式開(kāi)發(fā)時(shí)應(yīng)當(dāng)減少使用
- 適合以下條件都滿(mǎn)足的狀況
- 該內(nèi)容不會(huì)占用大量存儲(chǔ)資源
- 該內(nèi)容在整個(gè)生命周期都需要
- 該內(nèi)容幾乎不需要修改
- 該內(nèi)容在不同平臺(tái)設(shè)備都一致
Resources 序列化
項(xiàng)目編譯時(shí)會(huì)將所有 Resources 目錄下 Asset 和 Object 合并到一個(gè)序列化的 resources.assets
文件,該文件中還包含了類(lèi)似于 AssetBundle 的元數(shù)據(jù)(metadata)和索引信息榄融,該信息包含了由對(duì)象名稱(chēng)轉(zhuǎn)化得到的 GUID 和 Local ID 的查找樹(shù)和對(duì)象位于序列化文件中的字節(jié)偏移量
對(duì)于大部分平臺(tái)参淫,查找樹(shù)為時(shí)間復(fù)雜度為 O(n log(n)) 的平衡查找樹(shù),隨著 Resources 中對(duì)象的增加愧杯,索引加載時(shí)間增長(zhǎng)速度將超過(guò)線(xiàn)形增長(zhǎng)速度
Resources 系統(tǒng)在 Splash 展示時(shí)初始化涎才,該過(guò)程不可跳過(guò),經(jīng)觀察在低端設(shè)備上力九,10000 個(gè) Asset 文件就會(huì)導(dǎo)致該過(guò)程長(zhǎng)達(dá)數(shù)秒耍铜,哪怕很多對(duì)象在第一個(gè)場(chǎng)景沒(méi)用到也會(huì)被加載
接口 | 說(shuō)明 |
---|---|
FindObjectsOfTypeAll | 獲取所有指定類(lèi)型的對(duì)象 |
Load | 加載 Resources 指定目錄下的 Asset |
LoadAll | 加載 Resources 指定目錄下的所有 Asset |
LoadAsync | 異步加載 Resources 指定目錄下的 Asset |
UnloadAsset | 將 asset 從內(nèi)存釋放,重新加載 Asset 不會(huì)使之前的引用重新鏈接 |
UnloadUnusedAssets | 釋放未使用的 Asset(包括僅在腳本堆棧使用跌前,未在GameObject 使用) |
void Start()
{
//Load a text file (Assets/Resources/Text/textFile01.txt)
var textFile = Resources.Load<TextAsset>("Text/textFile01");
//Load text from a JSON file (Assets/Resources/Text/jsonFile01.json)
var jsonTextFile = Resources.Load<TextAsset>("Text/jsonFile01");
//Then use JsonUtility.FromJson<T>() to deserialize jsonTextFile into an object
//Load a Texture (Assets/Resources/Textures/texture01.png)
var texture = Resources.Load<Texture2D>("Textures/texture01");
//Load a Sprite (Assets/Resources/Sprites/sprite01.png)
var sprite = Resources.Load<Sprite>("Sprites/sprite01");
//Load an AudioClip (Assets/Resources/Audio/audioClip01.mp3)
var audioClip = Resources.Load<AudioClip>("Audio/audioClip01");
}
AssetBundle
AssetBundle 是外部資產(chǎn)的集合棕兼,可獨(dú)立于 Unity 構(gòu)建過(guò)程外,是 Unity 更新非代碼內(nèi)容的主要工具抵乓,經(jīng)常置于服務(wù)器上供用戶(hù)終端動(dòng)態(tài)獲瘸檀ⅰ蹭沛;AssetBundle 使開(kāi)發(fā)者可以提交更小的應(yīng)用包臂寝,最小化運(yùn)行時(shí)內(nèi)存壓力章鲤,使終端可以選擇性加載優(yōu)化內(nèi)容
該部分僅簡(jiǎn)單介紹 AssetBundle,更多信息可見(jiàn) Unity學(xué)習(xí)—AssetBundle
AssetBundle 構(gòu)建
-
首先分配資產(chǎn)對(duì)象所在 AssetBundle咆贬,在 Project 窗口選中需要打包的 Asset败徊,在 Inspect 窗口底部可見(jiàn)如下圖內(nèi)容,底部 AssetBundle 后有兩個(gè)輸入選擇框掏缎,第一個(gè)為該資源所在 AssetBundle 名稱(chēng)皱蹦,第二個(gè)為 AssetBundle 變體名稱(chēng)
除此之外,Unity 還提供了
AssetImporter.assetBundleName
和AssetImporter.assetBundleVariant
等接口將資源分配到 AssetBundle 然后即可構(gòu)建 AssetBundle 了眷蜈,使用
BuildPipeline.BuildAssetBundles()
即可構(gòu)建 AssetBundle沪哺,其中可配置參數(shù)輸出路徑、構(gòu)建選項(xiàng)酌儒、目標(biāo)平臺(tái)或者可以使用 Unity 官方提供的工具管理 AssetBundle AssetBundles-Browser 官方手冊(cè)
[MenuItem("Build Asset Bundles/Normal")]
static void BuildABsNone()
{
BuildPipeline.BuildAssetBundles("Assets/MyAssetBuilds", BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
}
AssetBundle 構(gòu)建選項(xiàng)
BuildAssetBundleOptions
- None
- UncompressedAssetBundle:不壓縮
- DisableWriteTypeTree:不包含類(lèi)型信息
- DeterministicAssetBundle:使用哈希值作為 Asset Id
- ForceRebuildAssetBundle:強(qiáng)制重建
- IgnoreTypeTreeChanges:增量構(gòu)建檢查時(shí)忽略類(lèi)型樹(shù)改動(dòng)
- AppendHashToAssetBundleName:AssetBundle 名稱(chēng)后加哈希值
- ChunkBasedCompression:使用 LZ4 壓縮
- StrictMode:構(gòu)建過(guò)程中任務(wù)錯(cuò)誤即構(gòu)建失敗
- DryRunBuild:試運(yùn)行
- DisableLoadAssetByFileName:禁用名稱(chēng)查找資源辜妓,可降低運(yùn)行時(shí)內(nèi)存提高加載效率
- DisableLoadAssetByFileNameWithExtension:禁用帶后綴名的名稱(chēng)查找資源,可降低運(yùn)行時(shí)內(nèi)存提高加載效率
AssetBundle 派發(fā)方式
根據(jù)實(shí)際情況選擇 AssetBundle 時(shí)隨項(xiàng)目打包忌怎,或后續(xù)通過(guò)網(wǎng)絡(luò)下載籍滴,一般移動(dòng)平臺(tái)由于初始安裝大小和下載限制,會(huì)選擇安裝后下載榴啸,而主機(jī)和電腦則隨項(xiàng)目打包
隨項(xiàng)目打包有兩個(gè)主要原因:
- 減少項(xiàng)目構(gòu)建時(shí)長(zhǎng)孽惰,簡(jiǎn)化迭代開(kāi)發(fā),針對(duì)無(wú)需單獨(dú)更新的 AssetBundle 可放在 StreamingAssets 目錄下
- 發(fā)布可更新的初始修正內(nèi)容鸥印,用于節(jié)省用戶(hù)初始安裝后的時(shí)間和為后續(xù)修復(fù)做準(zhǔn)備勋功。但 StreamingAssets 不適用于該情況,若不考慮自定義下載和緩存系統(tǒng)库说,則可以使用 Unity 的緩存系統(tǒng)狂鞋,從 StreamingAssets 下載初始緩存
一般推薦使用 UnityWebRequest
下載 AssetBundle,若下載包為 LZMA 壓縮璃弄,則緩存的為未壓縮或使用 LZ4 重壓縮的內(nèi)容要销,若緩存已滿(mǎn),則 Unity 會(huì)刪除最近最少使用的 AssetBundle
Unity 內(nèi)置的 AssetBundle 緩存系統(tǒng)用于緩存 UnityWebRequestAssetBundle.GetAssetBundle
下載的包夏块,緩存僅以名稱(chēng)作為唯一標(biāo)識(shí)疏咐。另外可通過(guò)重載方法可傳入版本號(hào)(開(kāi)發(fā)者自己管理版本號(hào)),緩存系統(tǒng)會(huì)比對(duì)版本號(hào)脐供,選擇匹配版本或下載新包
緩存系統(tǒng)可通過(guò) Caching.expirationDelay 和 Caching.maximumAvailableDiskSpace 修改最小未使用過(guò)期時(shí)間和最大緩存空間浑塞,當(dāng)緩存文件在過(guò)期時(shí)間內(nèi)沒(méi)被打開(kāi)過(guò)即被刪除,或緩存空間不足政己,則優(yōu)先刪除最近最少打開(kāi)的緩存
IEnumerator GetText()
{
using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle("http://www.my-server.com/mybundle"))
{
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.Log(uwr.error);
}
else
{
// Get downloaded asset bundle
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
}
}
}
AssetBundle 加載
有四種不同的 API 用于加載 AssetBundle酌壕,但每個(gè) API 的行為隨壓縮算法和平臺(tái)而不同
-
AssetBundle.LoadFromMemoryAsync
IEnumerator LoadFromMemoryAsync(string path) { AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); yield return createRequest; AssetBundle bundle = createRequest.assetBundle; var prefab = bundle.LoadAsset<GameObject>("MyObject"); Instantiate(prefab); }
-
AssetBundle.LoadFromFile
該方法可高效地從硬盤(pán)加載未壓縮或 LZ4 壓縮的 Assetbundle,加載 LZMA 壓縮包時(shí)會(huì)先解壓再加載到內(nèi)存
public class LoadFromFileExample : MonoBehaviour { function Start() { var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle")); if (myLoadedAssetBundle == null) { Debug.Log("Failed to load AssetBundle!"); return; } var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject"); Instantiate(prefab); } }
-
WWW.LoadfromCacheOrDownload(5.6 及以前版本)
舊方法,已拋棄
-
UnityWebRequestAssetBundle (5.3 及以后版本)
先使用
UnityWebRequest.GetAssetBundle
創(chuàng)建請(qǐng)求卵牍,再將請(qǐng)求傳入DownloadHandlerAssetBundle.GetContent(UnityWebRequest)
果港,下載完成后可像AssetBundle.LoadFromFile
一樣,直接使用 assetBundle 對(duì)象該方法使開(kāi)發(fā)者更靈活處理下載數(shù)據(jù)糊昙,選擇臨時(shí)存儲(chǔ)或長(zhǎng)期緩存辛掠,避免不必要的內(nèi)存使用。同時(shí)释牺,由于是原生代碼萝衩,沒(méi)有托管堆棧擴(kuò)展風(fēng)險(xiǎn),DownloadHandler 也不會(huì)保留下載數(shù)據(jù)没咙,進(jìn)一步減少了內(nèi)存開(kāi)銷(xiāo)
LZMA 壓縮包會(huì)在下載時(shí)解壓猩谊,并以 LZ4 重新壓縮緩存,可調(diào)用 Caching.CompressionEnabled 修改
IEnumerator InstantiateObject() { string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName; UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0); yield return request.Send(); AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request); GameObject cube = bundle.LoadAsset<GameObject>("Cube"); GameObject sprite = bundle.LoadAsset<GameObject>("Sprite"); Instantiate(cube); Instantiate(sprite); }
官方推薦盡量使用 AssetBundle.LoadFromFile
祭刚,該 API 在速度牌捷、磁盤(pán)使用和運(yùn)行時(shí)內(nèi)存使用方面都最高效;需要下載則使用 UnityWebRequest
AssetBundle Asset 加載
同步異步加載 Asset 一共有六種 API 可使用袁梗,同步方法一定比對(duì)應(yīng)的異步方法快至少一幀
- LoadAsset (LoadAssetAsync)
- LoadAllAssets (LoadAllAssetsAsync)
- LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)
LoadAllAssets
適合加載包中大部分或所有獨(dú)立 Unity 對(duì)象時(shí)使用宜鸯,相較于多次重復(fù)調(diào)用另外兩種 API,LoadAllAssets
速度要稍快一點(diǎn)遮怜。因此當(dāng) Asset 數(shù)量巨大且一次性需要加載的 Asset 少于 2/3 的時(shí)候淋袖,建議將 AssetBundle 拆分成多個(gè)小包體,再使用LoadAllAssets
加載
LoadAssetWithSubAssets
適合需要加載的對(duì)象內(nèi)嵌了其他對(duì)象的情況锯梁,若加載對(duì)象均來(lái)自于一個(gè) Asset 且包中有許多其他無(wú)關(guān)對(duì)象即碗,則使用該 API
其他情況均用LoadAsset (LoadAssetAsync)
Unity 對(duì)象加載時(shí)在主線(xiàn)程執(zhí)行,對(duì)象數(shù)據(jù)是在工作線(xiàn)程 worker thread陌凳,任何線(xiàn)程不敏感的操作都在工作線(xiàn)程執(zhí)行
異步加載時(shí)會(huì)根據(jù)時(shí)間片限制每幀加載多個(gè)對(duì)象剥懒,自 Unity 5.3 后,對(duì)象加載就并行化了合敦。多個(gè)對(duì)象在工作線(xiàn)程被反序列化初橘、處理和集成,當(dāng)對(duì)象加載完成充岛,則觸發(fā) Awake 回調(diào)
同步加載方法 AssetBundle.Load
會(huì)暫停主線(xiàn)程知道加載完成保檐,它們還將加載過(guò)程進(jìn)行時(shí)間切片,以使對(duì)象集成所占用的幀時(shí)間不超過(guò)特定的毫秒數(shù)崔梗,該值可通過(guò)Application.backgroundLoadingPriority
設(shè)定
- ThreadPriority.High: 最大 50 毫秒每幀
- ThreadPriority.Normal: 最大 10 毫秒每幀
- ThreadPriority.BelowNormal: 最大 4 毫秒每幀
- ThreadPriority.Low: 最大 2 毫秒每幀
在其他因素相同的情況下夜只,異步加載方法的調(diào)用到加載對(duì)象可用之間最小有一幀延遲,導(dǎo)致異步加載方法比同步方法執(zhí)行所需時(shí)間更長(zhǎng)
AssetBundle 依賴(lài)
根據(jù)運(yùn)行環(huán)境可以使用兩個(gè)不同的 API 自動(dòng)追蹤 AssetBundle 之間的依賴(lài)蒜魄。Editor 環(huán)境下扔亥,可使用AssetDatabase
查詢(xún)依賴(lài)场躯,使用AssetImporter
訪(fǎng)問(wèn)和修改 AssetBundle 的分配和依賴(lài);運(yùn)行時(shí)旅挤,可以通過(guò)基于 ScriptableObject 的 AssetBundleManifest
API 加載在 AssetBundle 構(gòu)建期間生成的依賴(lài)項(xiàng)信息
當(dāng)一個(gè)對(duì)象所在的 AssetBundle 被加載時(shí)踢关,該對(duì)象就被分配了一個(gè)唯一的有效實(shí)例 ID,因此 AssetBundle 的加載順序并不重要谦铃,重要的是在加載該對(duì)象本身之前耘成,要優(yōu)先把所有包含其依賴(lài)對(duì)象的 AssetBundle 加載好。
Unity 不會(huì)自動(dòng)加載子 AssetBundle驹闰,具體可詳見(jiàn)手冊(cè),例:
AssetBundle 1 中的 Material A 依賴(lài)于 AssetBundle 2 中的 Texture B撒会,若要正常加載嘹朗,與 AssetBundle 1 和 2 的加載順序無(wú)關(guān),但一定要保證加載 Material A 時(shí)诵肛,AssetBundle 2 已加載
在構(gòu)建 AssetBundle 時(shí)屹培,Unity 創(chuàng)建一個(gè)包含每一個(gè) AssetBundle 依賴(lài)信息的類(lèi)型為 AssetBundleManifest 的序列化對(duì)象,該文件存在一個(gè)與其他 AssetBundle 在同一打包路徑下的單獨(dú)的 AssetBundle 中怔檩,且與父層文件夾名相同
有兩種 API 查詢(xún)依賴(lài)
- AssetBundleManifest.GetAllDependencies 獲取 AssetBundle 的所有依賴(lài)層級(jí)
- AssetBundleManifest.GetDirectDependencies 獲取 AssetBundle 直接依賴(lài)
因該 API 會(huì)生成字符串?dāng)?shù)組褪秀,所以應(yīng)盡量少用,且避免性能高峰時(shí)使用
官方建議薛训,大部分場(chǎng)合下媒吗,在進(jìn)入性能需求高的場(chǎng)景前,盡可能多地加載對(duì)象乙埃,尤其對(duì)于移動(dòng)平臺(tái)這種闸英,訪(fǎng)問(wèn)本地存儲(chǔ)慢,加載卸載對(duì)象引起內(nèi)存流失會(huì)觸發(fā)垃圾回收的平臺(tái)
Asset 分包策略
- 邏輯實(shí)體分包
- 對(duì)象類(lèi)型分包
- 并發(fā)內(nèi)容分包
邏輯實(shí)體分包
依據(jù)資源在項(xiàng)目功能塊的使用位置介袜,如 UI甫何、角色、環(huán)境和其他在生命周期中常出現(xiàn)的內(nèi)容等分包
- 將所有 UI 的紋理和布局?jǐn)?shù)據(jù)分包
- 將角色的模型和動(dòng)畫(huà)數(shù)據(jù)分包
- 將多場(chǎng)景共用的紋理和模型分包
該分包方式適用于制作 DLC遇伞,可以只下載單個(gè)實(shí)體而無(wú)需下載無(wú)變化的資源辙喂,其關(guān)鍵點(diǎn)在于需要開(kāi)發(fā)者清楚了解每個(gè)打包的資源所要用到的時(shí)機(jī)和位置
對(duì)象類(lèi)型分包
該方式適用于針對(duì)多平臺(tái)分包,例如音頻文件的壓縮設(shè)置在 Windows 和 Mac OS 平臺(tái)一樣鸠珠,另外由于紋理壓縮格式和設(shè)置等改變頻率遠(yuǎn)低于腳本和預(yù)設(shè)體巍耗,使用該分配方式可以使 AssetBundle 兼容更多的 Unity 版本
并發(fā)內(nèi)容分包
并發(fā)內(nèi)容分包可理解為以關(guān)卡為分組依據(jù),將一個(gè)關(guān)卡內(nèi)獨(dú)有的角色跳芳、紋理芍锦、音樂(lè)等需要在同一時(shí)機(jī)加載的內(nèi)容分為一包
Tips
- 將常更新與不常更新內(nèi)容分開(kāi)
- 將需要同時(shí)加載的對(duì)象分為一組,如一個(gè)模型飞盆,其所需的材質(zhì)和動(dòng)畫(huà)分為一組
- 若多個(gè) AssetBundle 中的多個(gè)對(duì)象引用了其他 AssetBundle 中的單個(gè) Asset娄琉,則將依賴(lài)項(xiàng)分離到單獨(dú)的包中以減少重復(fù)
- 確保兩組完全不可能同時(shí)加載的對(duì)象不在用一包中次乓,如低清和高清材質(zhì)包
- 若一個(gè)包中只有低于一半的對(duì)象被頻繁加載,可將其拆分
- 將一些同時(shí)加載的小包(資源少于5到10個(gè))合并
- 若一個(gè)包中的對(duì)象僅是版本不同孽水,則可以使用 AssetBundle 變體
Addressable
Addressable 系統(tǒng)為 Unity 新推出的資源管理系統(tǒng)票腰,整合了 Unity 直接引用,Resources 和 AssetBundle 全部三種資源加載方式女气。通過(guò)可尋址資產(chǎn)的方式杏慰,便捷地實(shí)現(xiàn)了內(nèi)容包的創(chuàng)建和部署。Addressable 系統(tǒng)使用異步加載的方式實(shí)現(xiàn)從任何位置加載任何依賴(lài)項(xiàng)炼鞠,使得任何引用方式都更加便捷動(dòng)態(tài)化
注意:需Unity 2018.3 及其以后版本
Addressable 優(yōu)勢(shì)
- 縮減迭代周期缘滥,無(wú)需修改代碼優(yōu)化內(nèi)容
- 自動(dòng)依賴(lài)管理,將請(qǐng)求內(nèi)容的依賴(lài)項(xiàng)一同加載
- 自動(dòng)內(nèi)存管理谒主,對(duì)管理資源自動(dòng)引用計(jì)數(shù)
- 內(nèi)容打包朝扼,負(fù)責(zé)構(gòu)建和解析引用鏈,在將資源移動(dòng)或重命名的情況下霎肯,依然可實(shí)現(xiàn)本地和遠(yuǎn)端部署
- 配置文件擎颖,可配置多個(gè)配置文件,實(shí)現(xiàn)快速切換
Addressable 概念
Addressable 由兩個(gè)包組成观游,Addressable Assets package(主要功能) 和 Scriptable Build Pipeline package(依賴(lài)項(xiàng))
- Address:資源的地址標(biāo)記搂捧,用于運(yùn)行時(shí)查詢(xún)
- AddressableAssetData:在項(xiàng)目 Assets 目錄下用于存儲(chǔ) Addressable 資源的文件目錄
- Asset group:構(gòu)建時(shí)處理的 Addressable 資產(chǎn)組
- Asset group schema:數(shù)據(jù)構(gòu)建時(shí)的配置
- AssetReference:可根據(jù)需求延遲初始化的直接引用對(duì)象
- Asynchronous loading:開(kāi)發(fā)過(guò)程中無(wú)需更改代碼也可修改資產(chǎn)位置和依賴(lài)項(xiàng)
- Build script:打包資產(chǎn),將 Address 和 Resources 映射
- Label:為運(yùn)行時(shí)加載相似項(xiàng)目提供額外的 Addressable Asset 標(biāo)志
Addressable 使用
Addressable 安裝
-
打開(kāi)頂部工具欄 Window -> Package Manager懂缕,找到 Addressables允跑,點(diǎn)擊安裝即可
-
安裝完成后 Addressable 的主要功能都可在頂部工具欄 Window -> Asset Management -> Addressables 中找到
- Groups:Addressable 分組工具
- Settings:Addressable 總體設(shè)置
- Profiles:預(yù)設(shè)構(gòu)建配置管理
- EventViewer:監(jiān)測(cè)引用計(jì)數(shù)工具
- Analyze:用于分析打包情況,檢測(cè)重復(fù)等可自定義規(guī)則的分析工具
- Hosting:模擬服務(wù)器
-
打開(kāi)Group提佣,創(chuàng)建新的配置吮蛹,項(xiàng)目 Assets 目錄下會(huì)自動(dòng)創(chuàng)建一個(gè) AddressableAssetData 目錄,無(wú)需直接改動(dòng)該目錄
Addressable Group 配置
- 在 Addressables Groups 窗口拌屏,右鍵或左上角 create 按鈕即可創(chuàng)建 Group
- 選中 Group潮针,在 Inspector 中修改設(shè)置,Group 有三種配置項(xiàng)
- Content Packing & Loading:打包的構(gòu)建和加載路徑倚喂,以及其他打包相關(guān)設(shè)置
- Content Update Restriction:包更新限制
- Resources and Built In Scenes:是否包含 Resources 或構(gòu)建的場(chǎng)景
- 添加 Asset 后每篷,構(gòu)建 Addressable Group
- Addressables Groups 窗口,Build > New Build > Default Build Script
- 或者使用 API
AddressableAssetSettings.BuildPlayerContent()
Addressables Asset 配置和加載
-
添加 Addressable Asset
將資源直接拖入 Addressables Groups 窗口下分組內(nèi)即可
-
或者在 Project 中選擇任何 Asset 端圈,在 Inspector 下都可見(jiàn)名為 Addressable 的勾選框焦读,勾選即可將該 Asset,可更改其 Addressable 名稱(chēng)舱权,此時(shí)該 Asset 就被添加到默認(rèn)的 Addressables Group 中了
(可選) 更改資源名矗晃,為資源添加 Label
-
加載 Addressable Asset
-
Addressables.LoadAssetAsync<T>(string)
異步加載資源對(duì)象 -
Addressables.InstantiateAsync(string)
場(chǎng)景中創(chuàng)建對(duì)象 - 或添加
AssetReference
成員變量,在 Inspector 可選擇 AssetReference 引用的資源對(duì)象
public class AddressablesExample : MonoBehaviour { GameObject myGameObject; ... Addressables.LoadAssetAsync<GameObject>("AssetAddress").Completed += OnLoadDone; } private void OnLoadDone(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<GameObject> obj) { // In a production environment, you should add exception handling to catch scenarios such as a null result. myGameObject = obj.Result; } }
-