• Assetbundle2


    Assetbundle可以将Prefab封装起来,这是多么方便啊! 而且我也强烈建议大家将Prefab封装成Assetbundle,因为Prefab可以将游戏对象身上带的游戏游戏组件、游戏脚本、材质都封装在一起。当从服务器上将Assetbundle下载以后直接Instantiate就可以放入游戏中。

    无论是模型资源还是UI资源,最好是先把他们放在Prefab中,然后在做成Assetbundle

    如果打包场景的话那么内存与size就是 公用模型的size * N个场景,想想其实挺恐怖的。其实我们可以巧妙的使用,首先把场景中公用的部分和私有的部分统统放入Unity, 然后烘培整个场景。 当场景烘培完毕后把公用的模型部分在拿出去,场景只只保留私有的模型。还可以做一个工具将公用模型在场景中的坐标保存在XML中(每个场景文件会对应一个公用模型的XML信息),最后在将公用的模型分别封装在别的Assetbundle中。

           服务器上提供每个场景的Assetbundle ,和公用模型的Assetbundle,一般公用模型的Assetbundle可以放在常驻内存中(可能使用频繁、根据项目的不同而定)场景Assetbundle下载完毕后,现载入场景然后在根据场景对应的XML信息将公用模型部分动态的在添加到场景中,这样就完成了一个场景的构建。

    Prefab打包技巧: Prefab打包时自身是不占多少空间的 <=1KB  但是Prefab上是可以关联  这五大部分 “界面,模型,特效,声音,场景,脚本”以及在Hierarchy视图中 坐标/缩放/旋转。 关联这些信息以后就会很大,所以为了避免资源的浪费尽量避免Prefab重复关联。

    一个prefab下面可以同时关联多个游戏对象 ,这里举个例子如果你的 Prefab下面放了一个模型 它的大小可能是500k  ,在 Prefab下面放了十个完全相同模型 它的大小可能是501k 。 如果Prefab下面放了两个不同的模型,它的大小可能就会是 500k x 2 的size  ,也就是说Prefab与关联的数量是无关的 。 

    加密部分: assetbundle 是可以转换成 字节数组 ,客户端与服务器约定一组解密 字节数组的算法就可以实现资源加密。

    1、相同的模型尽量打包在一起,他们会公用一套资源文件。

    2、相同模型具有不同的脚本、组件的话把他们放在不同的Prefab中,最后把这些Prefab一起打包在一个Assetbundle中

    3、不相同的模型尽量分开打包

    对在Project视图中选中的对象进行分开打包:

     [MenuItem("Custom Editor/Create AssetBunldes Main")]
        static void CreateAssetBunldesMain()
        {
            //获取在Project视图中选择的所有游戏对象
            Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
            //遍历所有的游戏对象
            foreach (Object obj in SelectedAsset)
            {
                string sourcePath = AssetDatabase.GetAssetPath(obj);
                //本地测试:建议最后将Assetbundle放在StreamingAssets文件夹下,如果没有就创建一个,因为移动平台下只能读取这个路径
                //StreamingAssets是只读路径,不能写入
                //服务器下载:就不需要放在这里,服务器上客户端用www类进行下载。
                string path = CreatePath();
                string targetPath = path + obj.name + ".assetbundle";
                if (BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies))
                {
                    Debug.Log(obj.name + "资源打包成功");
                }
                else
                {
                    Debug.Log(obj.name + "资源打包失败");
                }
            }
            //刷新编辑器
            AssetDatabase.Refresh();
        }

    对在Project视图中选中的对象进行统一打包,打包成一个AB:

     [MenuItem("Custom Editor/Create AssetBunldes ALL")]
        static void CreateAssetBunldesALL()
        {
            Caching.CleanCache();
    
            string path = CreatePath();
            string Path = path + "ALL.assetbundle";
    
            Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
    
            //这里注意第二个参数就行
            if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, Path, BuildAssetBundleOptions.CollectDependencies))
            {
                AssetDatabase.Refresh();
            }
            else
            {
    
            }
        }
    
        private static string CreatePath()
        {
            string path = Application.dataPath + "/StreamingAssets/";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            return path;
        }

    BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies)

    参数1:它只能放一个对象,因为我们这里是分别打包,所以通过循环将每个对象分别放在了这里。

    参数2:可以放入一个数组对象。

    默认情况下打的包只能在电脑上用,如果要在手机上用就要添加一个参数。

    Android上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.Android)

    IOS上:BuildPipeline.BuildAssetBundle (obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies,BuildTarget.iPhone)

    另外,电脑上和手机上打出来的Assetbundle不能混用,不同平台只能用自己的。

    读取Assetbundle

    然后我们来学习如何运行时读取Assetbundle,Assetbundle是可以同时放在服务器或者本地的,无论放在哪里两种下载读取的方式是完全一样的

     //不同平台下StreamingAssets的路径是不同的,这里需要注意一下。
        public static readonly string PathURL =
    #if UNITY_ANDROID
            "jar:file://" + Application.dataPath + "!/assets/";
    #elif UNITY_IPHONE
            Application.dataPath + "/Raw/";
    #elif UNITY_STANDALONE_WIN || UNITY_EDITOR
     "file://" + Application.dataPath + "/StreamingAssets/";
    #else
            string.Empty;
    #endif
    
        void OnGUI()
        {
            //读取一个资源
            if (GUILayout.Button("Main Assetbundle"))
            {
                StartCoroutine(LoadMainGameObject(PathURL + "Cube1.assetbundle"));
                StartCoroutine(LoadMainGameObject(PathURL + "Cube2.assetbundle"));
            }
            //读取全部资源
            if (GUILayout.Button("ALL Assetbundle"))
            {
                StartCoroutine(LoadALLGameObject(PathURL + "ALL.assetbundle"));
            }
    
        }
    
        //读取一个资源
        private IEnumerator LoadMainGameObject(string path)
        {
            WWW bundle = new WWW(path);
            yield return bundle;
    
            //加载到游戏中   mainAsset只适用于ab里面只打包了一个对象
            yield return Instantiate(bundle.assetBundle.mainAsset);
            bundle.assetBundle.Unload(false);
        }
    
        //读取全部资源
        private IEnumerator LoadALLGameObject(string path)
        {
            WWW bundle = new WWW(path);
            yield return bundle;
    
            //通过Prefab的名称把他们都读取出来
            Object obj0 = bundle.assetBundle.Load("Cube1");
            Object obj1 = bundle.assetBundle.Load("Cube2");
    
            //加载到游戏中    
            yield return Instantiate(obj0);
            yield return Instantiate(obj1);
            bundle.assetBundle.Unload(false);
        }

    这里我们详细的说说 下载类WWW

    WWW bundle = new WWW(path);

    这样的做法是通过一个路径进行下载(无论是服务器路径还是本地路径下载操作都一样)但是bundle只能保存在内存中,也就是退出游戏在进入还得重新下,很显然在游戏中我们不能使用这种方式。

    private IEnumerator LoadMainCacheGameObject(string path)
        {
    //如果缓存中没有此ab,就去网络上下载 WWW bundle
    = WWW.LoadFromCacheOrDownload(path,5); yield return bundle; //加载到游戏中 yield return Instantiate(bundle.assetBundle.mainAsset); bundle.assetBundle.Unload(false); }

    使用的方法是WWW.LoadFromCacheOrDownload(path,5);

    参数1:服务器或者本地下载地址

    参数2:版本号

             Unity会下载Assetbundle本地中,它的工作原理是先通过(下载地址和版本号)先在本地去找看有没有这个Assetbundle,如果有直接返回对象,如果没有的话,再根据这个下载地址重新从服务器或者本地下载。这里版本号起到了很重要的作用,举个例子,同一下载地址版本号为1的时候已经下载到本地,此时将版本号的参数改成2 那么它又会重新下载,如果还保持版本号为1那么它会从本地读取,因为本地已经有版本号为1的这个Assetbundle了。你不用担心你的资源本地下载过多,也不用自己手动删除他们,这一切的一切Unity会帮我们自动完成,它会自动删除掉下载后最不常用的Assetbundle ,如果下次需要使用的话只要提供下载地址和版本后它会重新下载。

    我们再聊聊Assetbundle 中的脚本,在移动平台下Assetbundle里面放的脚本是不会被执行的,还记得我们打包前给两个Prefab挂上了脚本吗?在手机上将Assetbundle下载到本地后,加载进游戏中Prefab会自动在本地找它身上挂着的脚本,他是根据脚本的名来寻找,如果本地有这条脚本的话,Prefab会把这个脚本重新绑定在自身,并且会把打包前的参数传递进来。如果本地没有,身上挂的条脚本永远都不会被执行。

    如果你的Assetbundle中的Prefab上引用的对象,那么这样做就会出错了,你需要设定他们的依赖关系。或者运行时通过脚本动态的载入对象。

    http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.PopAssetDependencies.html

    http://docs.unity3d.com/Documentation/ScriptReference/BuildPipeline.PushAssetDependencies.html

    像这样重新打包就可以。但是,Unity官方表示这些方法都过时了,推荐使用Unity5.0以上的资源打包API了!可以避免很多坑!

    2014年10月补充

    WWW.LoadFromCacheOrDownload 这个方法建议大家以后不要再用了

    因为是异步方法,而且还占用内存。

    强烈建议使用AssetBundle.CreateFromFile 它是一个同步方法。现在IOS 和 android 都支持了,强烈建议用。

    打包的时候需要选择不压缩。

    //打包场景
                BuildPipeline.BuildStreamedSceneAssetBundle(levels, path, target, BuildOptions.UncompressedAssetBundle))
    //打包资源
                BuildPipeline.BuildAssetBundle(null, assets, path, BuildAssetBundleOptions.UncompressedAssetBundle | BuildAssetBundleOptions.CollectDependencies, target);

    因为不压缩, 所以就需要我们自己来压缩资源了, 可以用LZMA 和 GZIP来进行压缩。

    1.打包出来的Assetbundle我们自己用LZMA压缩,上传到服务器上。

    2.IOS或者Android下载这些assetbundle

    3.解压缩这些assetbundle并且保存在Application.persistentDataPath 目录下。

    4.以后通过AssetBundle.CreatFromFile  读取assetbundle。

    此法确实可行,我们已经在实际项目中轰轰烈烈的使用了。。

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

  • 相关阅读:
    安装yum源和gcc编译器遇到的问题
    (转)Linux下C++开发初探
    (转)求模和求余
    scanf———while(scanf ("%lu",&num) = =1)什么意思
    【Eclipse】 Alt+/ 代码提示问题解决方案
    【正则表达式】常用正则表达式
    【JAVA】Quartz中时间表达式的设置
    【Oracle】如何导库
    【JAVA】JMX简单使用方法
    【JAVA】Math.Round()函数常见问题“四舍5入”
  • 原文地址:https://www.cnblogs.com/MrZivChu/p/assetbundle2.html
Copyright © 2020-2023  润新知