1. 程式人生 > >《爐石傳說》架構設計賞析(4):Asset管理

《爐石傳說》架構設計賞析(4):Asset管理

歡迎轉載,請註明作者【燕良@遊戲開發】及原文地址:http://blog.csdn.net/neil3d/article/details/39580197
另外,歡迎大家來我的QQ群交流各種遊戲引擎相關的技術:遊戲引擎能吃嗎(264656505)

話說,經過這段時間的學習和摸索,對於Unity3D的開發思路已經基本清晰了。唯獨還剩下一個AssetBundle機制還沒有搞透,這個涉及到前期專案的資源規劃、資源管理程式碼的寫法,以及自動更新機制的實現。

所以,還是想先把遊戲邏輯的進一步分析押後,先來看一下《爐石傳說》Asset管理。必須得說一下的是,目前分析都是PC版的程式集,對於移動端不一定完全合適,且當做一個案例分析吧。

本文主要講述《爐石傳說》的AssetBundle的管理機制。它的機制比較簡單清晰,中規中矩,中間的分析過程就不講了,直接展現其架構設計和程式碼邏輯組織。先從Asset管理相關的類講起。

class Asset :資源資訊描述


Asset類,並不管理直接的資源物件,而是儲存的一個Asset相關的資訊,具體請看上圖。 另外,它還有一個“paths”變數,這是一個Dictionary,key是AssetFamily列舉,value是Assetbundle的路徑和資源路徑。下面的AssetFamily一節詳細解釋。

enum AssetFamily - 資源分類


如上圖所示:
  • 爐石根據資源的不同型別進行分別的AssetBundle打包,一類資源對應一個或者多個資源包;(一類資源分多個包的規則不得而知);
  • 有的資源包真的本地化單獨打包,例如“fonts0.unity3d”==》“fontszhCN0.unity3d”;
  • 在程式中,資源包的分類對應列舉型別“AssetFamily”;
  • 資源包的具體路徑資訊,儲存在Asset.paths,這是一個靜態變數;在初始化時,手動填寫必要的資訊,類似這樣:
        Dictionary<AssetFamily, AssetFamilyPathInfo> dictionary = new Dictionary<AssetFamily, AssetFamilyPathInfo>();
        AssetFamilyPathInfo info = new AssetFamilyPathInfo {
            format = "Data/Actors/{0}.unity3d",
            sourceDir = "Assets/Game/Actors"
        };
        info.exts = new string[] { "prefab" };
        dictionary.Add(AssetFamily.Actor, info);
    
  • 另外,還有一個class AssetBundleInfo是記錄了每種AssetBundle對應的主檔名,以及包檔案的個數、對應的物件型別等資訊;詳見下圖:

class AssetLoader :資源載入


遊戲執行時需要載入各種資源,基本上都是通過AssetLoader(也有個別情況適用了Resources.Load())。接下來我們就重點看一下AssetLoader的實現思路。
AssetLoader對上層提供資源物件載入介面,對於每種型別的資源都提供一組函式,例如LoadCardPrefab,LoadActor等等。對於物件載入完成、載入進度等提供回撥函式。這些函 數只是一些簡單的包裝,其內部都呼叫到 LoadCachedGameObject()或 LoadCachedObject()這兩個核心函式。 從這兩個函式的流程可以看到,資源載入使用到了Cache機制:
  • 首先從AssetCache中查詢,如果找到了,則更新Cache項的時間戳,並呼叫回撥;
  • 如果沒有找到,則向AssetCache新增一個Request,然後啟動Coroutine:CreateCachedAsset(),它的呼叫步驟是:
    • 呼叫AssetCache.StartLoading();
    • 啟動Coroutine:CreateCachedAsset_FromBundle<RequestType>():
      • 使用AssetLoader.GetBundleForAsset()找到資源所屬的AssetBundle;
      • 呼叫AssetBundle.LoadAsync()來真正載入資源;
      • 在載入的過程中,根據處理的結果呼叫:AssetCache.CacheRequest的OnLoadFailed()、OnLoadSucceeded()、OnProgressUpdate()等函式;
    • 在AssetCache查詢此資源,如果找到了,則載入成功,呼叫回撥函式;
      呼叫AssetCache.StopLoading();

我們都知道在開發過程中,不能使用AssetBundle(每次啟動都要打包,肯定收不了)。懷疑它的Editor模式相關的程式碼是用預編譯巨集處理來實現的,所以未出現在釋出出來的程式集當中,類似這樣:
#if UNITY_EDITOR
        Obj = Resources.LoadAssetAtPath(assetPath, typeof(T));
        if (Obj == null)
            Debug.LogError ("Asset not found at path: " + assetPath);
        yield break;
#else

class AssetCache :資源的Cache機制

前面在AssetLoader一節我們已經講到了AssetCache機制,這裡再做一個詳細的闡述。
前面我們已經講到:
  • AssetCache中的資源項的時間戳,由AssetLoader在資源載入請求時維護;
  • AssetCache主要負責管理Cache資料,而真正的資源載入動作還是在AssetLoader中執行;
AssetCache的資源淘汰主要由外部的各個模組根據自己認為需要的時機去呼叫,例如:
  • SceneMgr.ClearCachesAndFreeMemory()
  • LoadingScreen.ClearAssets()
  • SoundMgr.UnloadSoundBundle()
  • 等等
另外,程式啟動時會自動更新資源包(在Login.OnAssetsVersion()中啟動),主要是通過UpdateManager和Downloader兩個類來處理。 OK,總結一下爐石的資源管理機制:
  • 對遊戲資源按照型別分包,每一類資源包可以有多個;
  • 在遊戲執行時使用Cache機制;
最後,還是順便炫一下戰績: