Unity3d 5.x AssetBundle打包與加載

1.AssetBundle打包html

unity 5.x版本AssetBundle打包,只須要設置好AssetBundle的名稱後,unity會自動將其打包,無需處理其餘,惟獨須要作的是設置好個AssetBundle的名稱。緩存

注意:AssetBunlde的名稱只能設置小寫字母,即便你寫成大寫也會被自動轉置成大寫字母,並且名稱中支持「/」,如:「AssetBundles/cube.unity3d」,.unity3d的後綴是本身設置的,能夠不設置異步

代碼:ide

using UnityEngine;
using UnityEditor;
using System.IO;

public class CreateAssetBundles : Editor {

    [MenuItem("Tools/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        BuildPipeline.BuildAssetBundles(Application.dataPath + "/AssetBundles", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        Debug.LogWarning("打包成功");
    }

    [MenuItem("Tools/設置固定名")]
    public static void saveAsStaticName()
    {
        string Path = "Prefabs";
        string abName = "building.ab";
        SetVersionDirAssetName(Path, abName);//第一個參數是路徑 第二個參數是Ab名字 默認前綴爲 Application.dataPath + "/"+ Path  
    }

    [MenuItem("Tools/設定文件名")]
    public static void saveAsPrefabName()
    {
        string Path = "Prefabs";
        SetAssetNameAsPrefabName(Path);//第一個參數是路徑   
    }

    public static void SetVersionDirAssetName(string fullPath, string abName)
    {
        var relativeLen = fullPath.Length + 8; // Assets 長度  
        fullPath = Application.dataPath + "/" + fullPath + "/";

        if (Directory.Exists(fullPath))
        {
            EditorUtility.DisplayProgressBar("設置AssetName名稱", "正在設置AssetName名稱中...", 0f);
            var dir = new DirectoryInfo(fullPath);
            var files = dir.GetFiles("*", SearchOption.AllDirectories);
            for (var i = 0; i < files.Length; ++i)
            {
                var fileInfo = files[i];
                EditorUtility.DisplayProgressBar("設置AssetName名稱", "正在設置AssetName名稱中...", 1f * i / files.Length);
                if (!fileInfo.Name.EndsWith(".meta"))
                {
                    var basePath = fileInfo.FullName.Substring(fullPath.Length - relativeLen);//.Replace('\\', '/');  
                    var importer = AssetImporter.GetAtPath(basePath);
                    if (importer && importer.assetBundleName != abName)
                    {
                        importer.assetBundleName = abName;
                    }
                }
            }
            EditorUtility.ClearProgressBar();
        }
    }

    public static void SetAssetNameAsPrefabName(string fullPath)
    {
        var relativeLen = fullPath.Length + 8; // Assets 長度  
        fullPath = Application.dataPath + "/" + fullPath + "/";

        if (Directory.Exists(fullPath))
        {
            EditorUtility.DisplayProgressBar("設置AssetName名稱", "正在設置AssetName名稱中...", 0f);
            var dir = new DirectoryInfo(fullPath);
            var files = dir.GetFiles("*", SearchOption.AllDirectories);
            for (var i = 0; i < files.Length; ++i)
            {
                var fileInfo = files[i];
                string abName = fileInfo.Name;
                EditorUtility.DisplayProgressBar("設置AssetName名稱", "正在設置AssetName名稱中...", 1f * i / files.Length);
                if (!fileInfo.Name.EndsWith(".meta"))
                {
                    var basePath = fileInfo.FullName.Substring(fullPath.Length - relativeLen);//.Replace('\\', '/');  
                    var importer = AssetImporter.GetAtPath(basePath);
                    //abName = AssetDatabase.AssetPathToGUID(basePath);
                    if (importer && importer.assetBundleName != abName)
                    {
                        importer.assetBundleName = abName;
                    }
                }
            }
            EditorUtility.ClearProgressBar();
        }
    }

    /// <summary>  
    /// AssetBundleManifestName == 對應AB依賴列表文件  
    /// </summary>  

    private static string AssetBundle_BuildDirectory_Path = @Application.streamingAssetsPath + "/../../../" + "AssetBundles";
    private static string AssetBundle_TargetDirectory_Path = @Application.streamingAssetsPath + "/" + "ABFiles";
    [MenuItem("Tools/Asset Bundle/Build Asset Bundles", false, 0)]
    public static void BuildAssetBundleAndroid()
    {
        //Application.streamingAssetsPath對應的StreamingAssets的子目錄  
        DirectoryInfo AB_Directory = new DirectoryInfo(AssetBundle_BuildDirectory_Path);
        if (!AB_Directory.Exists)
        {
            AB_Directory.Create();
        }
        FileInfo[] filesAB = AB_Directory.GetFiles();
        foreach (var item in filesAB)
        {
            Debug.Log("******刪除舊文件:" + item.FullName + "******");
            item.Delete();
        }
#if UNITY_ANDROID
        BuildPipeline.BuildAssetBundles(AB_Directory.FullName, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);  
#elif UNITY_IPHONE
        BuildPipeline.BuildAssetBundles(AB_Directory.FullName, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.iOS); 
#else
        BuildPipeline.BuildAssetBundles(AB_Directory.FullName, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);
#endif
        Debug.Log("******AssetBundle打包完成******");

        Debug.Log("將要轉移的文件夾是:" + AssetBundle_TargetDirectory_Path);
        FileInfo[] filesAB_temp = AB_Directory.GetFiles();

        DirectoryInfo streaming_Directory = new DirectoryInfo(AssetBundle_TargetDirectory_Path);

        FileInfo[] streaming_files = streaming_Directory.GetFiles();
        foreach (var item in streaming_files)
        {
            item.Delete();
        }
        AssetDatabase.Refresh();
        foreach (var item in filesAB_temp)
        {
            if (item.Extension == "")
            {
                item.CopyTo(AssetBundle_TargetDirectory_Path + "/" + item.Name, true);
            }
        }
        AssetDatabase.Refresh();
        Debug.Log("******文件傳輸完成******");
    }

    private static string _dirName = "";
    /// <summary>  
    /// 批量命名所選文件夾下資源的AssetBundleName.  
    /// </summary>  
    [MenuItem("Tools/Asset Bundle/Set Asset Bundle Name")]
    static void SetSelectFolderFileBundleName()
    {
        UnityEngine.Object[] selObj = Selection.GetFiltered(typeof(Object), SelectionMode.Unfiltered);
        foreach (Object item in selObj)
        {
            string objPath = AssetDatabase.GetAssetPath(item);
            DirectoryInfo dirInfo = new DirectoryInfo(objPath);
            if (dirInfo == null)
            {
                Debug.LogError("******請檢查,是否選中了非文件夾對象******");
                return;
            }
            _dirName = dirInfo.Name;

            string filePath = dirInfo.FullName.Replace('\\', '/');
            filePath = filePath.Replace(Application.dataPath, "Assets");
            AssetImporter ai = AssetImporter.GetAtPath(filePath);
            ai.assetBundleName = _dirName;

            SetAssetBundleName(dirInfo);
        }
        AssetDatabase.Refresh();
        Debug.Log("******批量設置AssetBundle名稱成功******");
    }
    static void SetAssetBundleName(DirectoryInfo dirInfo)
    {
        FileSystemInfo[] files = dirInfo.GetFileSystemInfos();
        foreach (FileSystemInfo file in files)
        {
            if (file is FileInfo && file.Extension != ".meta" && file.Extension != ".txt")
            {
                string filePath = file.FullName.Replace('\\', '/');
                filePath = filePath.Replace(Application.dataPath, "Assets");
                AssetImporter ai = AssetImporter.GetAtPath(filePath);
                ai.assetBundleName = _dirName;
            }
            else if (file is DirectoryInfo)
            {
                string filePath = file.FullName.Replace('\\', '/');
                filePath = filePath.Replace(Application.dataPath, "Assets");
                AssetImporter ai = AssetImporter.GetAtPath(filePath);
                ai.assetBundleName = _dirName;
                SetAssetBundleName(file as DirectoryInfo);
            }
        }
    }
    /// <summary>  
    /// 批量清空所選文件夾下資源的AssetBundleName.  
    /// </summary>  
    [MenuItem("Tools/Asset Bundle/Reset Asset Bundle Name")]
    static void ResetSelectFolderFileBundleName()
    {
        UnityEngine.Object[] selObj = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Unfiltered);
        foreach (UnityEngine.Object item in selObj)
        {
            string objPath = AssetDatabase.GetAssetPath(item);
            DirectoryInfo dirInfo = new DirectoryInfo(objPath);
            if (dirInfo == null)
            {
                Debug.LogError("******請檢查,是否選中了非文件夾對象******");
                return;
            }
            _dirName = null;

            string filePath = dirInfo.FullName.Replace('\\', '/');
            filePath = filePath.Replace(Application.dataPath, "Assets");
            AssetImporter ai = AssetImporter.GetAtPath(filePath);
            ai.assetBundleName = _dirName;

            SetAssetBundleName(dirInfo);
        }
        AssetDatabase.Refresh();
        Debug.Log("******批量清除AssetBundle名稱成功******");
    }
}
View Code

上述代碼中有一些測試函數,使用時可進行測試函數

 

2.AssetBundle加載工具

下述代碼中,cube,sphere等都是在unity項目中本身建立的3d預製體,自行建立便可。建立完成使用1中的方法打包AssetBundle。注意代碼中的cube大小寫問題,小寫的是設置的AssetBundle名稱,大寫的是Cube預製體的名稱,不要混淆。測試

代碼:優化

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AssetBundleLoad : MonoBehaviour {

    // Use this for initialization
    void Start () {
        this.load1();
        //this.load2();
        //this.load3();
        //this.load4();
    }

    void load1()
    {
        //1.先加載cube後加載sphere
        //這種方式並無先加載cube的依賴文件,按理說應該加載出來的cube上是sphere是missing的,可是unity5.6.3f1
        //加載並未missing,不知是否是unity版本的優化,不過好習慣仍是先加載依賴文件,如load2()。

        //加載assetbundlemanifest文件
        AssetBundle assetBundleManifest = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/AssetBundles");
        if(null != assetBundleManifest)
        {
            AssetBundleManifest manifest = assetBundleManifest.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

            //加載cube
            AssetBundle bundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/cube.prefab");
            GameObject obj = bundle.LoadAsset<GameObject>("Cube");
            if(null != obj)
            {
                GameObject cube = Instantiate(obj);
                cube.transform.SetParent(GameObject.Find("UIRoot").transform);
            }

            //加載cube的依賴文件
            string[] depends = manifest.GetAllDependencies("cube.prefab");
            AssetBundle[] dependsAssetbundle = new AssetBundle[depends.Length];
            for(int index = 0; index < depends.Length; ++index)
            {
                dependsAssetbundle[index] = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/" + depends[index]);

                obj = dependsAssetbundle[index].LoadAsset<GameObject>("Sphere");
                if (null != obj)
                {
                    GameObject sphere = Instantiate(obj);
                    sphere.transform.SetParent(GameObject.Find("UIRoot").transform);
                }
            }
        }
    }

    void load2()
    {
        //2.先加載sphere再加載cube

        //加載assetBundleManifest文件
        AssetBundle assetBundleManifest = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/AssetBundles");
        if(null != assetBundleManifest)
        {
            AssetBundleManifest manifest = assetBundleManifest.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

            //加載cube依賴文件
            string[] depends = manifest.GetAllDependencies("cube.prefab");
            AssetBundle[] dependsAssetbundle = new AssetBundle[depends.Length];
            for (int index = 0; index < depends.Length; ++index)
            {
                dependsAssetbundle[index] = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/" + depends[index]);

                GameObject obj1 = dependsAssetbundle[index].LoadAsset<GameObject>("Sphere");
                if (null != obj1)
                {
                    GameObject sphere = Instantiate(obj1);
                    sphere.transform.SetParent(GameObject.Find("UIRoot").transform);
                }
            }

            //加載cube
            AssetBundle bundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/cube.prefab");
            GameObject obj = bundle.LoadAsset<GameObject>("Cube");
            if(null != obj)
            {
                GameObject sphere = Instantiate(obj);
                sphere.transform.SetParent(GameObject.Find("UIRoot").transform);
            }
        }
    }

    void load3()
    {
        //3.只加載cube不加載sphere

        //無需加載assetBundleManifest文件,直接加載cube
        AssetBundle bundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/cube.prefab");
        GameObject obj = bundle.LoadAsset<GameObject>("Cube");
        if (null != obj)
        {
            GameObject sphere = Instantiate(obj);
            sphere.transform.SetParent(GameObject.Find("UIRoot").transform);
        }
    }

    void load4()
    {
        //4.兩個預製打包成同一個AssetBundle

        //無需加載assetBundleManifest文件,直接加載cube
        AssetBundle bundle = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/cube2.prefab");
        GameObject obj = bundle.LoadAsset<GameObject>("Cube_1");
        if (null != obj)
        {
            GameObject cube = Instantiate(obj);
            cube.transform.SetParent(GameObject.Find("UIRoot").transform);
        }

        obj = bundle.LoadAsset<GameObject>("Cube_2");
        if (null != obj)
        {
            GameObject cube = Instantiate(obj);
            cube.transform.SetParent(GameObject.Find("UIRoot").transform);
        }
    }
}
View Code
using UnityEngine;

public class Relation : MonoBehaviour {
    //掛在cube預製上的測試腳本
    public GameObject sphere_go;
    public GameObject capsule_go;
    // Use this for initialization
    void Start () {
        ScriptRelation t = new ScriptRelation();
        t.printLog();
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}
View Code
using UnityEngine;

public class ScriptRelation{

    public void printLog()
    {
        Debug.Log("xxxxxxxxxxxxxxxxxx");
    }
}
View Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestAssetBundle : MonoBehaviour {

    public string AssetBundleName = "cube";

    private string dir = "";
    private AssetBundle bundle = null;
    private Object asset = null;
    private GameObject go = null;

    private AssetBundleManifest manifest = null;

    // Use this for initialization
    void Start () {
        dir = Application.dataPath + "/AssetBundles/";
    }
    
    void OnGUI()
    {
        if (GUILayout.Button("LoadAssetBundle", GUILayout.Width(200), GUILayout.Height(50))) { LoadBundle(); }
        if (GUILayout.Button("LoadAsset", GUILayout.Width(200), GUILayout.Height(50))) { LoadAsset(); }
        if (GUILayout.Button("Instantiate", GUILayout.Width(200), GUILayout.Height(50))) { Instantiate(); }
        if (GUILayout.Button("Destory", GUILayout.Width(200), GUILayout.Height(50))) { Destroy(); }
        if (GUILayout.Button("Unload", GUILayout.Width(200), GUILayout.Height(50))) { UnLoad(); }
        if (GUILayout.Button("UnloadForce", GUILayout.Width(200), GUILayout.Height(50))) { UnLoadForce(); }
        if (GUILayout.Button("UnloadUnusedAssets", GUILayout.Width(200), GUILayout.Height(50))) { UnloadUnusedAssets(); }

        //bundle依賴包加載
        if (GUILayout.Button("LoadAssetBundleManifest", GUILayout.Width(200), GUILayout.Height(50))) { LoadAssetBundleManifest(); }
        if (GUILayout.Button("LoadBundleAndDeps", GUILayout.Width(200), GUILayout.Height(50))) { LoadBundleAndDeps(); }
    }

    void LoadBundle()
    {
        bundle = AssetBundle.LoadFromFile(System.IO.Path.Combine(dir, AssetBundleName));
        if(null == bundle)
        {
            Debug.LogError("LoadBundle Failed");
        }
    }

    void LoadAsset()
    {
        if (null == bundle) return;

        asset = bundle.LoadAsset<Object>("Cube");
        if (null == asset) Debug.LogError("LoadAsset Failed");
    }

    void Instantiate()
    {
        if (null == asset) return;

        go = GameObject.Instantiate<Object>(asset) as GameObject;
        if (null == go) Debug.LogError("Instantiate Failed");
        else
        {
            go.transform.SetParent(GameObject.Find("UIRoot").transform);
        }
    }

    void Destroy()
    {
        if (null == go) return;

        GameObject.Destroy(go);
        go = null;
    }

    /**
     *  AssetBundle.unload(bool unloadAllLoadedObjects) 接口用來卸載AssetBundle文件。
     *  參數爲false時,調用該接口後,只會卸載AssetBundle對象自身,並不會影響AssetBundle中加載的Assets。
     *  參數爲true時,除了AssetBundle對象自身,全部從當前AssetBundle中加載的Assets也會被同時卸載,無論這個Assets是否還在使用中。
     *  官方推薦參數通常設置爲false,只有當很明確知道從AssetsBundle中加載的Assets不會被任何對象引用時,纔將參數設置成true。
     **/
    void UnLoad()
    {
        if (null == bundle) return;

        bundle.Unload(false);
        //GameObject.Instantiate<Object>(asset);  //asset可用
        asset = null;
        bundle = null;
    }

    void UnLoadForce()
    {
        if (null == bundle) return;

        bundle.Unload(true);
        //GameObject.Instantiate<Object>(asset);  //報錯:asset已被銷燬
        asset = null;
        bundle = null;
    }

    void UnloadUnusedAssets()
    {
        Resources.UnloadUnusedAssets();
    }

    void LoadAssetBundleManifest()
    {
        var bundle = AssetBundle.LoadFromFile(System.IO.Path.Combine(dir, "AssetBundles"));
        manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //unload
        bundle.Unload(false);
        bundle = null;
    }

    void LoadBundleAndDeps()
    {
        string bundleName = "cube";

        string[] dependence = manifest.GetDirectDependencies(bundleName);
        for(int i=0; i<dependence.Length; ++i)
        {
            AssetBundle.LoadFromFile(System.IO.Path.Combine(dir, dependence[i]));
        }

        var bundle = AssetBundle.LoadFromFile(System.IO.Path.Combine(dir, bundleName));
        var asset = bundle.LoadAsset<GameObject>("Cube");
        bundle.Unload(false);
        bundle = null;
        go = GameObject.Instantiate<GameObject>(asset);
    }
}
View Code

上述代碼有兩個測試腳本,AssetBundleLoad.cs只作了AssetBudle加載的測試。TestAssetBundle.cs作了AssetBundle加載,卸載,使用等測試,比較完整。ui

 

3.unity項目中的3個特殊文件夾this

a.Resources(只讀)

Resources文件夾下的資源會被所有打包到apk或者ipa裏面,至關與一個unity默認的AssetBundle,按理說是能夠將遊戲中全部的資源所有放在Resources進行加載,可是

Resources下的文件數量會影響遊戲的啓動速度,越多越慢。其次遊戲爲了下降drawcall,須要對相同材質的圖像打包圖集,可是若是放在Resources裏面是無法打包圖集的。

Resources下的資源打包時會進行壓縮

b.StreamingAssets(只讀)

StreamingAssets文件夾下的資源會被所有打包到apk或者ipa裏面

StreamingAssets文件夾下的資源不會影響遊戲啓動速度

StreamingAssets文件夾下的資源不會被壓縮,因此佔用內存較大

c.persistentDataPath(可讀寫)

persistentDataPath文件夾在unity項目中是不存在的,他是程序的沙盒文件夾,只有你遊戲安裝完成以後,纔會存在這個目錄,可是它可讀寫。

 

綜上三種文件夾,咱們本身在使用時,Resources裏面放的資源只是在本地開發階段使用,打包的時候會把Resources中的文件都考本出去打成AssetBundle包,而後再將打包好的AssetBundle放到StreamingAssets文件夾下打包apk。

遊戲運行時再將資源考本到persistentDataPath文件夾下,由於這個目錄可讀寫,因此可以用來作資源熱更新。

 

若有錯誤,敬請指正。

 

///////////****如下摘自:http://www.cnblogs.com/jiangshuai52511/p/6437239.html  做者:涼城舊巷舊少年 ******/////////

5.3.針對項目的建議

因爲以上分析的幾種加載手段各有各的使用情景和特色。所以建議在咱們的項目中按照如下情景使用這些方法:

  • 隨遊戲一同發佈的AssetBundle(通常位於StreamingAssets文件夾中):
  • 在打AssetBundle包時,使用LZ4壓縮格式進行打包(開啓BuildAssetBundleOptions.ChunkBasedCompression便可)。
  • 在運行時須要加載AssetBundle對象時,使用LoadFromFile方法進行加載。
  • 這樣作的好處是:便可以將AssetBundle文件壓縮,又能夠兼顧加載速度,且節約內存。
  • 做爲更新包,須要從服務端下載的AssetBundle:
  • 在打AssetBundle包時,使用默認的LZMA格式壓縮。
  • 使用方法下載並緩存AssetBundle包文件。
  • 這樣作的好處是:得到了最大的壓縮率,在下載過程當中能夠減小數據傳輸量。同時,在本地磁盤建立緩存以後,又能夠兼顧以後的加載速度,且節約內存。
  • 咱們本身進行加密的AssetBundle:
  • 在打AssetBundle包時,使用LZ4壓縮格式進行打包(開啓BuildAssetBundleOptions.ChunkBasedCompression便可)。
  • 在運行時須要加載AssetBundle對象時,使用LoadFromMemory方法進行加載。(這也是從內存中使用流數據加載AssetBundle對象的僅有的使用場景。)
  • 咱們本身壓縮的AssetBundle:
  • 咱們本身也可使用第三方庫或工具對生成的AssetBundle包文件進行壓縮,若是須要這樣作,則咱們最好不要再使用Unity3D對 AssetBundle進行壓縮,所以在打包時選擇開啓 BuildAssetBundleOptions.UncompressedAssetBundle。
  • 在運行時須要加載AssetBundle對象時,使用LoadFromFileAsync方法進行異步加載。

///////////****以上摘自:http://www.cnblogs.com/jiangshuai52511/p/6437239.html  做者:涼城舊巷舊少年 ******/////////

 

 

參考文章:

http://www.xuanyusong.com/archives/3229

http://www.cnblogs.com/AaronBlogs/p/6837682.html

http://www.cnblogs.com/kanekiken/p/7533510.html

http://www.cnblogs.com/murongxiaopifu/p/4199541.html

http://www.cnblogs.com/jiangshuai52511/p/6437239.html

http://blog.csdn.net/u010377179/article/category/6413676/3

http://blog.csdn.net/suifcd/article/details/51570003

 

AssetBundle內存相關:

http://blog.csdn.net/sgnyyy/article/details/39268215

相關文章
相關標籤/搜索