Unity5.x AssetBundle依赖项打包详解

Unity5.x AssetBundle依赖项打包详解

在这段时间一直在研究AssetBundle,从什么都不懂到今天算是研究透了,特写下这边文章来记录下。并且也给后面的学习者一个学习的机会,让他们少花一点时间去研究。

1、准备工作


在网上有很多AssetBundle的代码和资料,让人眼花缭乱,有些有问题或者有些有太简单了。不过还好Unity官方提供了一个关于AssetBundle的免费插件,基本上可以拿过来用,然后根据需求自己修改就可以了。
这里写图片描述
下载好导入到自己的项目中即可,这个插件官方还提供了几个Demo场景,稍微认真看一些就会用了,然后后期在仔细研究它的代码。

2、开始打包

1. 准备资源
打包时如果只单独打包预制物体,那么Unity会将这个预制物体相关的所有依赖项都打包进去(纹理,材质,Shader等)。一旦这个预制物体多了,那么资源包的大小将会非常大。而且也不方便后续的维护,幸好Unity已经帮我们都处理好了,我们只需要进行打包就好,非常简单。


首先,下图是我们的预制物体、以及纹理、材质、Shader
这里写图片描述

这里写图片描述

这里写图片描述
这里写图片描述


2. 开始打包

资源准备完毕,下面开始打包。
Shader打包
选中所有的Shader,然后在Inspector下方的AssetBundle进行打包即可。
这里写图片描述
这里写图片描述
这样子我们就实现了场景中Shader的打包,非常的简单。
材质打包
同理材质打包也是这样子。
这里写图片描述
纹理打包
这里写图片描述
预制物体打包
预制物体打包也是一样的。即使你在这个预制物体挂上脚本也没关系。
这里写图片描述
现在我们就AssetBundle打包完毕了。但是这个AssetBundle包目前是看不到的,所以需要提取出来显示在本地上。

这里可能会有人会问,我只想打包我的预制物体呀,没必要打包这些材质,纹理,Shader呀。可能我们这里演示时只用了两个物体,不能很直观的展示。当我们在真实项目上应用时,很多预制物体的材质,纹理,Shader其实是公用的,如果我们单独的针对预制物体打包,那么Unity会见预制物体相关的所有东西都打成一个包。
而现在我们把纹理、材质、Shader都打成一个后,那么后续预制物体打包时,就不会把这些纹理、材质、Shader在打进自己的包中了,但是它会依赖纹理、材质、Shader的这个包,这样子就节省了很多空间。
后续会有图片展示。


3. 提取包

导入前面我们说的插件后,点击Assets/AssetBundles/Build AssetBundles的“Build AssetBundles”按钮,然后进行等待。
这里写图片描述
注意:在这里是比较容易出问题的,一种是AssetBundle路径出现了问题,问题的原因可能是你设置的路径,但是并没有资源用这个路径。那么可以点击“Remove Unused Names”把一些无用的路径去掉,如果提取资源时还出现问题,那么你就需要重新创建一个项目将资源重新导入了。
这里写图片描述
打包完成后,会在项目的根目录生成资源文件。
这里写图片描述
这里写图片描述
仔细观察我们可以发现,”lan”文件是我们的材质、纹理、Shader“AssetBundle”后的路径,lan.manifest文件是一些依赖项信息,这个文件是很重要的,所以千万别删除了。
“测量摩擦”和”测量平均速度”这两个文件是我们的预制物体文件,观察两个文件的大小37k和9k。如果你单独的针对这两个物体打包。不按上述的将材质、纹理、Shader也打包,那么两个资源的大小是1M多,因为它会将这个预制物体所有相关的依赖性都打包进去。可能大家会问lan文件包含了13M呀,这个我们要注意lan文件是包含了场景中的所有材质、纹理、Shader。而我们的两个预制物体只用到了这其中的很小部分。但是当有N多个预制物体要AssetBundle时,那么这个节省的空间将是很大的。

很有意思的是,如果你新建一个项目里面什么都没有,然后写一些代码解析这些资源包。把这两个预制物体生成在场景中,你会发现它们是没有任何问题的。


4. 编写解析包代码
现在我们要写代码去解析这个包,并且显示在场景中去。 核心代码插件里都写好了,而且也很简单。基本上依葫芦画瓢。

//AssetBundlesOutputPath是资源包的路径,不用指定某个文件的路径。只需要指定资源文件夹的路径即可。
public const string AssetBundlesOutputPath = "/AssetBundles/";
//这是我自定义的类,用来存储预制物体的路径以及预制物体的名字
public List<ResourcesInfo> listInfo;
//当程序退出时,需要把资源删除掉。这个是路径,这只是用来测试的。
public string _unloadAssetBundle;
//Text,用来显示加载了哪个资源包。
public Text text;
[System.Serializable]
public class ResourcesInfo
{
    public string assetBundleName;
    public string assetName;
}

将这个脚本挂在物体上去即可。
这里写图片描述
继续编写后续的代码。

 void OnDestroy()
 {
     AssetBundleManager.UnloadAssetBundle(listInfo[0].assetBundleName);
     AssetBundleManager.UnloadAssetBundle(_unloadAssetBundle);
     Resources.UnloadUnusedAssets();
     System.GC.Collect();
 }
//当程序退出时进行一些处理,我也不知道这个处理有什么用,对我的内存也没什么很大的明显,但是这么写估计是好的吧。
//大部分代码都是这个插件的Demo脚本提供的,只不过修改了下而已。
//利用协程执行Start方法,这样子做只有当第一个资源加载完毕后,才会执行下一个资源的加载。
IEnumerator Start()
{
    yield return StartCoroutine(Initialize());
    for (int i = 0; i < listInfo.Count; i++)
    {
      yield return StartCoroutine(InstantiateGameObjectAsync(listInfo[i].assetBundleName, listInfo[i].assetName));
    }
        ////yield return new WaitForSeconds(2f);
        //StartCoroutine(LoadingPrint());
 }

 protected IEnumerator Initialize()
 {
        //DontDestroyOnLoad(gameObject);

#if DEVELOPMENT_BUILD || UNITY_EDITOR
        AssetBundleManager.SetDevelopmentAssetBundleServer();
#else
        // Use the following code if AssetBundles are embedded in the project for example via StreamingAssets folder etc:
        //如果AssetBundles嵌入在项目中,例如通过StreamingAssets文件夹等,请使用以下代码:
        AssetBundleManager.SetSourceAssetBundleURL("file://" + Application.dataPath + AssetBundlesOutputPath);
        // Or customize the URL based on your deployment or configuration
        //或者根据部署或配置自定义URL
        //AssetBundleManager.SetSourceAssetBundleURL("http://www.MyWebsite/MyAssetBundles");
#endif

        // Initialize AssetBundleManifest which loads the AssetBundleManifest object.
        //初始化载入AssetBundleManifest对象的AssetBundleManifest。
        var request = AssetBundleManager.Initialize();
        if (request != null)
            yield return StartCoroutine(request);
    }

    protected IEnumerator InstantiateGameObjectAsync(string assetBundleName, string assetName, bool isInit = false)
    {
        // This is simply to get the elapsed time for this phase of AssetLoading.
        float startTime = Time.realtimeSinceStartup;

        // Load asset from assetBundle.
        AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(assetBundleName, assetName, typeof(GameObject));
        if (request == null)
            yield break;
        yield return StartCoroutine(request);

        // Get the asset.
        GameObject prefab = request.GetAsset<GameObject>();

        if (prefab != null)
        {
            var go = Instantiate(prefab);
            go.name = prefab.name;

            Init(go);
        }

        // Calculate and display the elapsed time.
        float elapsedTime = Time.realtimeSinceStartup - startTime;
        //Debug.Log(assetName + (prefab == null ? " was not" : " was") + " loaded successfully in " + elapsedTime + " seconds");
    }

    public void Init(GameObject go)
    {
        text.text += go.name + "加载完成" + "\r\n";
    }

这里写图片描述
需要注意的是红色框框标记的是程序打包后,资源包的路径。如果是Windows本地的话在前面要加”file://”,如果是其他的平台要根据自己的情况而定。这里需要注意下。
程序打包
将程序打包后,我们需要手动的将资源放在程序的根目录下,你也可以根据自己的情况从服务器下载或者其他的路径,但是一定要跟你代码的路径要一致,否则是没办法加载出来的。
这里写图片描述
运行程序。
这里写图片描述
这样我们就将资源从程序分离出来了,当美术要更新资源时,直接更新lan的资源即可。不过还有代码的热更新没有说,因为代码的热更新我也在边研究边学习。只有在实际项目开发后,才能去衡量和准备。

其实整篇文章基本上用的都是Unity官方提供的,我们并没有写什么代码,只是根据自己的需求修改了一下而已。如果想具体去了解里面的原理可以去看插件内的源码。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值