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”);//固定加载方式,通过 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值