zoukankan      html  css  js  c++  java
  • Unity3d 5.x AssetBundle打包与加载

    1.AssetBundle打包

    unity 5.x版本AssetBundle打包,只需要设置好AssetBundle的名称后,unity会自动将其打包,无需处理其他,唯独需要做的是设置好个AssetBundle的名称。

    注意:AssetBunlde的名称只能设置小写字母,即使你写成大写也会被自动转置成大写字母,而且名称中支持“/”,如:“AssetBundles/cube.unity3d”,.unity3d的后缀是自己设置的,可以不设置

    代码:

    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加载,卸载,使用等测试,比较完整。

    3.unity项目中的3个特殊文件夹

    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

  • 相关阅读:
    (转)iOS7界面设计规范(2)
    (转)iOS7界面设计规范(1)
    (转)iOS7人机界面设计规范
    (转)iOS Wow体验
    (转)iOS Wow体验
    (转)iOS Wow体验
    (转)iOS Wow体验
    bzoj1044木棍分割
    bzoj1690开关灯
    终于开了blog了。。
  • 原文地址:https://www.cnblogs.com/lan-yt/p/7787290.html
Copyright © 2011-2022 走看看