Unity AssetBundle加載

通過AssetBundle加載遊戲資源,分爲兩步:

  1. 加載AssetBundle對象。
  2. 通過AssetBundle對象加載需要的資源。

本地沒有AssetBundle,需要先從網絡下載AssetBundle:

1.Unity5.2之前推薦使用 WWW.LoadFromCacheOrDownload(),慢慢被淘汰掉了。(異步加載,每次打包都需要更新資源版本,下載後緩存的資源也不好管理)

  • Unity會先判斷本地有無"url"的文件,如果沒有,就會根據URL去下載相應的文件。然後在本地存儲一下文件,並記錄相應的版本號。
  • Unity會先判斷本地有"url"的文件,本地的版本號<API傳入的版本號,此時Unity也會去下載最新的文件,然後覆蓋本地的此文件,然後記錄下最新的版本號。
  • Unity會先判斷本地有"url"的文件,本地的版本號>=API傳入的版本號,此時Unity會從本地直接取,並且加載相應的文件返回。
  • Caching.ClearCache() 刪除本地緩存。

2.WWW下載保存AssetBundle到本地

/// <summary>
///從服務器下載到本地
/// </summary>
/// <param name="AssetsHost">服務器路徑</param>
/// <param name="AssetName">請求資源名稱</param>
/// <param name="saveLocalPath">保存到本地路徑,一般存在Application.persistentDataPath</param>
/// <returns></returns>
IEnumerator DownLoadAssetsWithDependencies2Local(string AssetsHost, string AssetName, string saveLocalPath)
{
    WWW tempWwwAsset = new WWW(AssetsHost + "/" + AssetName);
    //獲取加載進度
    yield return tempWwwAsset;

    //直接讀取AssetBundle
    AssetBundle temp = tempWwwAsset.assetBundle;

    //保存到本地
    Stream tempStream = null;
    FileInfo fileInfo = new FileInfo(saveLocalPath + "/" + AssetName);
    if (fileInfo.Exists)
    {
        fileInfo.Delete();
    }
    //如果此文件不存在則創建
    tempStream = fileInfo.Create();
    //寫入
    tempStream.Write(tempWwwAsset.bytes, 0, tempWwwAsset.bytes.Length);
    tempStream.Flush();
    //關閉流
    tempStream.Close();
    //銷燬流
    tempStream.Dispose();
    Debug.Log(name + "成功保存到本地~");
}

 

3.UnityWebRequest下載AssetBundle到本地(據說用www下載在IOS平臺會出現卡死,用這不會)

IEnumerator Download(Action callback = null) 
{
    string tempSrcUrl = string.Empty;//傳入資源網址
    string saveLocalPath = string.Empty;//保存到本地的路勁
    UnityWebRequest tempWebRequest = UnityWebRequest.Get(tempSrcUrl);
    //設置超時,若m_webRequest.SendWebRequest()連接超時會返回,且isNetworkError爲true
    tempWebRequest.timeout = 30;
    yield return tempWebRequest.SendWebRequest();

    if(tempWebRequest.isNetworkError) {
        Debug.Log("Download Error:" + tempWebRequest.error);
    } else {

        //直接讀取AssetBundle
        AssetBundle tempAssetBundle = (tempWebRequest.downloadHandler as 
        DownloadHandlerAssetBundle).assetBundle;

        //保存到本地
        string tempAssetBundleName = (tempWebRequest.downloadHandler as 
        DownloadHandlerAssetBundle).assetBundle.name;
        byte[] bytes = tempWebRequest.downloadHandler.data;
        Stream tempStream = null;
        FileInfo fileInfo = new FileInfo(saveLocalPath + "/" + tempAssetBundleName);
        if (fileInfo.Exists)
        {
            fileInfo.Delete();
        }
        //如果此文件不存在則創建
        tempStream = fileInfo.Create();
        //寫入
        tempStream.Write(bytes, 0, bytes.Length);
        tempStream.Flush();
        //關閉流
        tempStream.Close();
        //銷燬流
        tempStream.Dispose();
        Debug.Log(name + "成功保存到本地~");
        tempWebRequest.Dispose();
        tempWebRequest = null;
    }

    if(callback != null) {
        callback();
    }
}

AssetBundle加載:

AssetBundle.LoadFromFile() - 同步加載

AssetBundle tempLogo = AssetBundle.LoadFromFile(AssetBundlesOutputPath + "/logo.unity3d");

AssetBundle.LoadFromFileAsync() - 異步加載

IEnumerator LoadAsyncCoroutine(string path, Action<AssetBundle> callback) {
    AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(path);
    yield return abcr;        
    callback(abcr.assetBundle);
}

WWW - 異步加載

IEnumerator LoadFromWWWCoroutine(string path, Action<AssetBundle> callback)
{
    WWW www = new WWW(path);
    yield return www;
    callback(www.assetBundle);
    www.Dispose();
    www = null;
}

LoadFromMemoryAsync - 異步加載

IEnumerator LoadAB(string _filePath)
{
    byte[] tempByteAry = File.ReadAllBytes(_filePath);
  AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(tempByteAry);
  yield return request;
  AssetBundle ab = request.assetBundle;
}

WWW.LoadFromCacheOrDownload - 異步加載

IEnumerator LoadCacheOrDownloadFromFile(string path)
{
  while (Caching.ready == false)
  yield return null;

  WWW www = WWW.LoadFromCacheOrDownload(path, 1);
  yield return www;

  if( !string.IsNullOrEmpty(www.error) )
  {
    Debug.Log(www.error);
    yield break;
  }
  AssetBundle ab = www.assetBundle;
}

AssetBundle加載後,從已加載的AssetBundle中加載資源:

AssetBundle tempAssetBundle = 通過上邊代碼獲取的AssetBundle;
string[] tempAssetNames = tempAssetBundle.GetAllAssetNames();//此AssetBundle中包含的所有資源名稱
tempAssetBundle.LoadAsset("");//通過資源名稱從AssetBundle加載指定的資源
tempAssetBundle.LoadAllAssets();//加載當前資源包中所有的資源
tempAssetBundle.LoadAssetAsync("");//從資源包中異步加載資源

加載AssetBundle時候,此AssetBundle依賴其他AssetBundle,需要先加載其他AssetBundle。

    [MenuItem("AssetsBundle/Load")]
    static void LoadAssetbundle()
    {
        LoadAssetBundleManifest();
        LoadBundle();
	}

    //本地AssetBundle存儲路勁 自己存哪讀哪
    private static string m_rootFilePath = Application.dataPath + "/StreamingAssets/";
    private static AssetBundleManifest manifest = null;

    // 加載Manifest
    private static void LoadAssetBundleManifest()
    {
        var bundle = AssetBundle.LoadFromFile(System.IO.Path.Combine(m_rootFilePath,"StreamingAssets"));
        manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        // 壓縮包釋放掉
        bundle.Unload(false);
        bundle = null;
    }

    //加載AssetBundle前,先加載AssetBundle依賴的AssetBundle
    private static void LoadBundle()
    {
        string bundleName = "logo";
        // GetAllDependencies會返回直接和間接關聯的AssetBundle 當前AssetBundle所依賴的所有AssetBundle
        // 加載依賴包沒有順序要求,
        string[] dependence = manifest.GetAllDependencies(bundleName);
        for (int i = 0; i < dependence.Length; ++i )
        {
            //這地方同步加載,異步也可以(AssetBundle.LoadFromFileAsync)
            AssetBundle.LoadFromFile(System.IO.Path.Combine(m_rootFilePath, dependence[i]));
        }
        //加載完所有依賴的AssetBundle,加載本身
        var bundle = AssetBundle.LoadFromFile(System.IO.Path.Combine(m_rootFilePath, bundleName));
        //這裏不需要手動LoadAsset 依賴的AssetBundle中資源
        //LoadAsset(logo) 資源的時候自動加載與它關聯的Asset
        GameObject tempGameObject = bundle.LoadAsset<GameObject>("logo");
        GameObject tempGameObject1 = Instantiate(tempGameObject) as GameObject;
    }

        //這裏不需要手動LoadAsset 依賴的AssetBundle中資源
        //LoadAsset(logo) 資源的時候自動加載與它關聯的Asset

AssetBundle中可以實例化的類型:

Texture 設置read/write enabled後可以
AudioClip 不可以
Scene 可以
TextAsset 可以,但一般沒有必要
Material 可以
Shader 可以
Mesh 可以
Animator 可以
Animation 可以
TerrainData 可以
GameObject 可以,Prefab就是GameObject,一般都是實例化prefab,實例化其他的沒有必要。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章