資源模塊做什么?
資源模塊——ResourceModule,是KEngine中最核心的模塊,其他模塊基本或多或少的對它有依賴,它主要的功能是:資源打包、路徑定義、資源管理、資源調試。
資源模塊對Unity的Asset Bundle接口進行了完整的封裝,運行模式下可以使用它進行完整的資源加載、卸載,也可以通過它方便地查找資源內存泄露的問題。
AssetBundle自動化打包
Unity 5中,Asset Bundle系統做了很大的變化。你只需將需要打包的資源配置AssetBundle Name,然后執行接口BuildPipeline.BuildAssetBundles(outputPath)就完成了所有AssetBundle的打包,比Unity 4.x方便多了。
圖:把需要打包的資源放到BundleResources目錄中
圖:AssetBundle最終默認生成到Product/Bundles/(Platform)/中
圖:KEngine->AssetBundle->Build All,自動設置BundleResources目錄下所有的資源的Asset Bundle Name並執行打包
在KEngine+Unity 5.x中,把配置AssetBundle Name的這一步也省掉了。你只需把需要打包的資源,放在Assets/BundleResources目錄中,所有的AssetBundle將會完整導出。
路徑定義
Unity跨平台開發中,針對不同的平台——如編輯器、安卓、IOS、Windows等,一般有不同的資源存放路徑。
像生成的Asset Bundle,還需要針對不同的平台,生成完全不一樣的Asset Bundle資源。
因而KEngine中分別對Unity中的StreamingAssetsPath、PersistentDataPath等做了封裝,開發人員無需為資源放在什么目錄進行煩惱了(詳見ResourceModule中的InitResourcePath方法),並且,內置了支持熱更新。
舉例:加載一個Asset Bundle的路徑選擇
假設現在要加載一個UI資源"Login":
public IEnumerator LoadUIAsset(CUILoadState loadState, UILoadRequest request) { string path = string.Format("ui/login.prefab.bytes")); var assetLoader = KStaticAssetLoader.Load(path); while (!assetLoader.IsCompleted) yield return null; request.Asset = assetLoader.TheAsset; // Asset 是GameObject }
這個StaticAssetLoader,做了什么操作?假設我們在Android平台
- 獲知ui/login.prefab.bytes這個路徑
- 尋找熱更新資源,嘗試加載PersistentAssetsPath/Bundles/Android/ui/logins.prefabs.bytes
- 無法找到熱更新資源,嘗試加載StreamingAssetsPath/Bundles/Android/ui/logins.prefabs.bytes
- 依然無法找到,加載失敗
資源加載
KEngine在Unity 5.x中,會自動的先加載依賴資源,你只要填入Asset Bundle的路徑名字就可以了。就像Unity的Resources類一樣。
簡單加載
使用ResourceModule中的LoadBundle、LoadBundleAsync接口,可以實現類似於Unity的Resources.Load、Resources.LoadAsync的效用。
要注意的是,LoadBundle、LoadBundleAsync接口,起始地址是加載StreamingAssets/Bundles/Win32或StreamingAssets/Bundles/Android這種平台相關的路徑。
// 同步加載,返回加載器,加載器中有加載的資源 var reqeust = ResourceModule.LoadBundle("ui/login.prefab.bytes") Debug.Log(request.Asset != null); // true // 異步加載,返回加載器,加載器中還沒加載的資源,需要異步等待 var request = ResourceModule.LoadBundleAsync("ui/login.prefab.bytes", (isOk, asset, args)=>{}); Debug.Log(request.Asset == null); // true
Loader加載器
KEngine中定義了各種類型的資源加載器,提供更為方便的加載、調試功能,來避免一些使用上的。坑
Loader加載器
加載GameObject
最常用的Loader有兩個:
- StaticAsset:每次調用Load,使用同一份GameObject引用
- InstanceAsset:每次調用Load,都會拷貝出一份GameObject
// 協程風格 public IEnumerator LoadUIAsset(UILoadRequest request) { string path = string.Format("ui/login.prefab.bytes")); var assetLoader = KStaticAssetLoader.Load(path); while (!assetLoader.IsCompleted) yield return null; request.Asset = assetLoader.TheAsset; // Asset 是GameObject }
// CPS回調風格 public void LoadUIAsset(UILoadRequest request) { string path = string.Format("ui/login.prefab.bytes")); KStaticAssetLoader.Load(path, (isOk, asset, args)=>{ request.Asset =asset; }); }
資源的釋放
KEngine中的資源釋放,跟Unity的資源釋放明顯區別是:Unity中提供Resources.UnloadUnusedAssets接口,來自動釋放無用的資源的。而KEngine中資源釋放采用純手動的方式。
這主要是因為躺過Unity自動釋放資源的很多坑: 經常會遇到“missing”的資源引用吧?因此選擇了手動釋放機制。
所有XXXLoader,都有一個接口Loader.Release(),舉例:
string path = string.Format("ui/login.prefab.bytes")); var assetLoader = KStaticAssetLoader.Load(path); // 引用計數1 while (!assetLoader.IsCompleted) yield return null; var assetLoader2 = KStaticAssetLoader.Load(path); // 引用計數2 while (!assetLoader2.IsCompleted) yield return null; assetLoader2.Release(); // 釋放,減小引用計數 // 引用計數1 assetLoader.Release(); // 引用計數0,正式刪掉緩存的資源
手工釋放的資源存在引用計數,只有當引用計數為0,Loader才會觸發回收,並且連同加載過的AssetBundle徹底消滅,節省內存。
其它Loader
諸如TextureLoader、AudioLoader等等,所有XXXLoader的使用方法都是一致的,它們提供CPS回調風格和協程風格
資源的調試監控
在Unity Editor模式下,所有的XXXLoader加載類實例,都會伴隨住一個GameObject的產生,而這個GameObject,只用於進行調試、內存信息查看:
圖:資源加載調試信息:Loader、加載的對象
圖:每一個Loader的引用計數信息,都可以通過面板來進行實時查看
如上圖所示,通過KEngine的資源調試器,可以方便的找到加載的AssetBundle的資源對象、監控內存占用的大小、Loader加載消耗的時間、Loader當前引用計數等信息。對比Unity原生的Profiler,這些信息是即時的。 開發人員可以非常方便的尋找資源泄露問題,優化內存占用。
版權說明
文/公的Kelly[mr-kelly](簡書作者) Email: 23110388@qq.com
原文鏈接:http://www.jianshu.com/p/ce3b5d0bdf8c
著作權歸作者所有,轉載請聯系作者獲得授權,,並標注“簡書作者”。
KSFramework系列
github地址:https://github.com/mr-kelly/KSFramework
歡迎大家到 github提issues