Unity5.x新依赖打包及加载

写在前面:

很久很久很久。。没有更新了,当然写这个需要坚持,最近因为工作调整转了移动开发,之后的博客更新会以移动开发为主了,当然写博客纯粹是为了记录自己的学习过程,毕竟好记性不如硬键盘嘛,有什么错误的地方还望大家指正。

Unity自5.0开始提供了新的AssetBundle打包Api,以下是新旧Api对比:

旧版:
图1
图1


打包方式:

public class ExportAssetBundles {
        [MenuItem("Assets/Build AssetBundle From Selection - Track dependencies")]
        static void ExportResource () {
            // Bring up save panel
            string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
            if (path.Length != 0) {
                // Build the resource file from the active selection.
                Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
                BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, 0);
                Selection.objects = selection;
            }
        }
        [MenuItem("Assets/Build AssetBundle From Selection - No dependency tracking")]
        static void ExportResourceNoTrack () {
            // Bring up save panel
            string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
            if (path.Length != 0) {
                // Build the resource file from the active selection.
                BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
            }
        }
    }

而在目前最新的Unity2017版本中,旧版本的打包方式已经被完全废弃了。

新版打包Api:

图2
图2


public class PackageAssetBundle : MonoBehaviour {
    [MenuItem("Build/Build AssetBundles")]
    static void buildAssetBundles()
    {
        string buildPath = Application.dataPath + "/Assets/Abs";//打包路径
        if (!Directory.Exists(buildPath))
            Directory.CreateDirectory(buildPath);
        BuildPipeline.BuildAssetBundles(buildPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }

}

可以看到打包的代码非常简单。

如何指定需要打包的assets?

有几种方式:
第一种是直接在Inspecot面板进行指定:
图3
图3


打包时Api将选择所有你指定了AssetBundle VarName的资源,然后统一进行打包,如图3中该资源被打包后最终会生成cube.ab和cube.ab.manifest两个文件,manifest文件中记录的是cube.ab的信息,如依赖资源等等。

第二种呢是在代码中进行指定:

public class BuildAssetBundlesBuildMapExample : MonoBehaviour
{
    [MenuItem("Example/Build Asset Bundles Using BuildMap")]
    static void BuildMapABs()
    {
        // Create the array of bundle build details.
        AssetBundleBuild[] buildMap = new AssetBundleBuild[2];

        buildMap[0].assetBundleName = "enemybundle";

        string[] enemyAssets = new string[2];
        enemyAssets[0] = "Assets/Textures/char_enemy_alienShip.jpg";
        enemyAssets[1] = "Assets/Textures/char_enemy_alienShip-damaged.jpg";

        buildMap[0].assetNames = enemyAssets;
        buildMap[1].assetBundleName = "herobundle";

        string[] heroAssets = new string[1];
        heroAssets[0] = "char_hero_beanMan";
        buildMap[1].assetNames = heroAssets;

        BuildPipeline.BuildAssetBundles("Assets/ABs", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }
}

当然指定方式灵活度还是不错的,你可以直接Selection,然后再对Selection的资源构造成buildMap,再进行处理即可。

打包说完了,接着就是加载咯。

如何加载?

加载可以分为三个步骤:
1.首先读取Manifest文件,读取需要加载ab(AssetBundle)的依赖资源
2.加载依赖ab
3.加载ab

ok,说了这么多好像。。。

那好吧,接下来还是看个小例子吧.

打包资源如下:

图4
图4


依赖关系:

Prefabs depends Materials
cube.ab depend on texure.ab
capsule.ab depend on emission.ab

我们只需要把材质挂在prefabs上即可,Unity新的打包方式会自动帮我们处理依赖关系的,运行打包代码后得到如下目录:
图5
图5
show in explorer来看看:
图6
图6
如图6所示,打包完成后,在打包路径下生成了一个和当前路径文件夹同名的AssetBundle文件和一个manifest文件,这两个文件是有用的,别随便删除了哈。。。这里写图片描述

但是改个名字什么的还是可以的哈。

接着来看一下文件大小,毕竟我们使用依赖打包的目的是为了减小包的大小不是嘛:

ab size
cube.ab 1.72KB
capsule.ab 1.78KB
texure.ab 147KB
emission.ab 510KB

哎,没错的吧,cube和capsule中确实剔除了材质,大小只有一点多KB,来看一下依赖信息,就是它:
图7
图7
我们可以发现里面清晰的记录每个ab的依赖资源信息。


加载方式

AssetBundle的加载方式有好几种,这里介绍两种常用的:

1.LoadFromFile:

public GameObject loadAssetBundleFiles(string filePath, string manifestBundleName, string abFileName, string prefabFileName)
    {
        /**
         * 1.首先从打包路径获取依赖
         * 这里加载的就是生成的同名文件ab,这里应该是filePath/Abs,当然会这个名称也可以修改
         */
        AssetBundle manifestBundle = AssetBundle.LoadFromFile(getManifestFilePath(filePath, manifestBundleName));
        /**
         * 2.获取依赖资源列表
         */
        if (manifestBundle != null)
        {
            try
            {
                AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//固定加载方式,通过 assetbundle Abs加载Abs.manifest
                manifestBundle.Unload(false);
                //获取加载ab的依赖信息,参数为ab名称,如cube.ab
                string[] dependsFile = manifest.GetAllDependencies(abFileName);
                if (dependsFile.Length > 0)
                {
                    //根据获取到的依赖信息加载所有依赖资源ab
                    AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
                    for (int i = 0; i < dependsFile.Length; i++)
                    {
                        String fp = generateAbsoluteFile(filePath, dependsFile[i]);
                        Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
                        dependsBundle[i] = AssetBundle.LoadFromFile(fp);
                    }
                }
            }
            catch (InvalidCastException e)
            {
                Debug.LogException(e);
            }

            /**
             * 3.最后加载ab
             * 注意这里的LoadAsset的参数是Prefab的名称,无后缀,如cube而非cube.ab或cube.prefab
             */
            AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
            GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
            ab.Unload(false);
            return go;
        }
        return null;
    }

2.WWW加载:

IEnumerator wwwGetAssetBundles(string filePath, string manifestName, string abFileName, string prefabFileName)
    {
        //WWW www = WWW.LoadFromCacheOrDownload(getManifestFilePath(filePath), 0);
        WWW www = new WWW(manifestName);
        yield return www;
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.LogError(www.error);
        }
        else
        {
            /**
             * 1.首先从打包路径获取依赖
             */
            AssetBundle manifestBundle = www.assetBundle;
            /**
             * 2.获取依赖资源列表
             */
            if (manifestBundle != null)
            {

                AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
                manifestBundle.Unload(false);
                www.Dispose();
                string[] dependsFile = manifest.GetAllDependencies(abFileName);
                if (dependsFile.Length > 0)
                {
                    AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
                    for (int i = 0; i < dependsFile.Length; i++)
                    {
                        String fp = generateAbsoluteFile(filePath, dependsFile[i]);
                        Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
                        www = new WWW(fp);
                        yield return www;
                        if(www.error == null)
                        {
                            dependsBundle[i] = www.assetBundle;
                            www.Dispose();
                        }                        
                    }
                }

                /**
                 * 3.最后加载ab
                 */
                AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
                GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
                if (go != null)
                {
                    GameObject.Instantiate(go);
                }
                ab.Unload(false);
            }
        }
    }

代码和第一种加载方式大致相同。

最后说一点使用时需要注意的地方,举个例子,比如说我们有一公用的资源,A、B、C三个ab都需要依赖D,那么在程序中我们需要加载A时会先加载D,然后加载A,这个时候B也需要被加载了,因为程序不知道D已经被加载了,所以再次去读取依赖信息,尝试加载D,这样就会消耗一些cpu的时间了,因此在我们实际开发中应该更加合理的去管理公用的ab资源,对于不常用的公用ab使用过后及时卸载,下次使用再进行加载,而对用经常使用需要常驻内存的ab资源,最好在程序中设置一个标识,标记其是否已经被加载,存在于内存中,然后在加载依赖该公用ab的ab资源时判断该公用ab是否已被加载,当然,也可能会存在一个ab依赖多个公用资源,这种情况就需要开发者更加谨慎的去处理依赖关系了,最好建立统一的管理,做到逻辑清晰。

Over:最后贴出
官网链接:BuildAssetBundles
Demo下载链接(Unity5.x):Demo地址
密码:m4q2


发布了7 篇原创文章 · 获赞 4 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览