牛骨文教育服务平台(让学习变的简单)
博文笔记

Unity 关于AssetBundle(资源束)打包和加载(一)

创建时间:2017-02-22 投稿人: 浏览次数:6282

在使用Unity制作大型场景的时候,往往需要加载大量的数据文件,尤其是对于模型、材质、贴图、特效等资源都是项目中不可缺少的一部分。数据量越大,数组加载就越慢,让用户长时间等待是一种非常差的体验。

因此在项目制作前必须先要解决场景数据管路的问题。Unity3D提供了一种被叫做 AssetBundles(资源束)的外部整合数据,可以供我们资源管理使用。

在游戏的运作当中,更新资源必不可少。我们可以将他们制作成Prefab,包成AssetBundle,方便我们后面使用来达到资源更新的效果。


1.首先在场景中新建3个物体,分别是:Cube,Sphere, Capsule,分别把他们拉成预制体。
这里写图片描述


2.分别点击预制体,给每个预制体设置 AssetBundle 的名字
这里写图片描述这里写图片描述这里写图片描述

这里我们对AssetBundle 下拉框这里面的选项进行一下解释!~
这里写图片描述

None: 表示AssetBundle的名称为空
New…:设置AssetBundle的名称(名称默认小写表示)
Remove Unused Names: 移除没有使用到的 AssetBundle的名称
Filter Selected Name: 筛选出使用该AssetBundle名称的所有物体


3.上面的AssetBundle的名称设置好之后,我们开始编写——打包脚本(脚本放在Editor文件夹下)

using UnityEditor;
using UnityEngine;

public class BuildAssetBundle{

    /// <summary>
    /// 点击后,所有设置了AssetBundle名称的资源会被 分单个打包出来
    /// </summary>
    [MenuItem("AssetBundle/Build (Single)")]
    static void Build_AssetBundle()
    {   
        BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        //刷新
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 选择的资源合在一起被打包出来
    /// </summary>
    [MenuItem("AssetBundle/Build (Collection)")]
    static void Build_AssetBundle_Collection()
    {
        AssetBundleBuild[] buildMap = new AssetBundleBuild[1];
        //打包出来的资源包名字
        buildMap[0].assetBundleName = "enemybundle";

        //在Project视图中,选择要打包的对象  
        Object[] selects = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
        string[] enemyAsset = new string[selects.Length];
        for (int i = 0; i < selects.Length; i++)
        {
            //获得选择 对象的路径
            enemyAsset[i] = AssetDatabase.GetAssetPath(selects[i]);
        }
        buildMap[0].assetNames = enemyAsset;

        BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        //刷新
        AssetDatabase.Refresh();
    }
}

上面打包AssetBundle的代码,主要一句

//“Application.dataPath + /Test_AssetBundle” --AssetBundle导出到的文件夹的位置
//“BuildAssetBundleOptions.None” --构建AssetBundle没有任何特殊的选项
//“BuildTarget.StandaloneWindows” --AssetBundle的构建平台(这个需要注意,这里测试的电脑端,Android、IOS等需要另外选择) 
BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);

打包出来的 AssetBundle
这里写图片描述
这里打包的 “enemybundle”, 我选择的是三个预设体(Cube、Sphere、Capsule)打包在了一起;


这里显示的打包出来的AssetBundle包含的物体的信息
这里写图片描述


4.打包脚本编写完成后,接下来编写——读取脚本

using System.Collections;
using UnityEngine;

public class LoadAssetBundle : MonoBehaviour{

    public static string BundleURL;

    private void Awake()
    {
        //平台预处理
        BundleURL =
#if UNITY_ANDROID
                    "jar:file://" + Application.dataPath + "!/assets/";
#elif UNITY_IPHONE
                    Application.dataPath + "/Raw/";  
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
                    "file://" + Application.dataPath + "/Test_AssetBundle/";//Test_AssetBundle 资源束文件的位置 
#else
                    string.Empty;  
#endif
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(20,20,300,100),"点击加载Asset"))
        {
            //BundleURL + "enemybundle" 要加载的文件地址
            StartCoroutine(DownLoadAssetAndScene(BundleURL + "cub"));
            //StartCoroutine(DownLoadAssetAndScene(BundleURL + "sph"));
            //StartCoroutine(DownLoadAssetAndScene(BundleURL + "cap"));
            //StartCoroutine(DownLoadAssetAndScene(BundleURL + "enemybundle"));
        }
    }

    IEnumerator DownLoadAssetAndScene(string path)
    {
        //电脑端加载使用
        WWW asset = new WWW(path);

        yield return asset;
        AssetBundle bundle = asset.assetBundle;
        //资源加载 
        //加载的是打包到资源包里面,每个资源的名字
        Instantiate(bundle.LoadAsset("Cube.prefab"));
        //Instantiate(bundle.LoadAsset("Sphere.prefab"));
        //Instantiate(bundle.LoadAsset("Capsule.prefab"));

        //资源加载完毕后记得Unload,不然再次加载资源的时候无法加载
        bundle.Unload(false);
    }
}

加载出来资源的位置就是AssetBundle时候,资源在场景中的位置。

值得一提的是,在加载完资源后立即通过AssetBundle.Unload(false)释放AssetBundle(资源束)文件本身的内存镜像,但不销毁加载的Asset(资源)对象。这样就不用保存AssetBundle(资源束)的引用,且可以立即释放一部分内存。释放时,如果有Instantiate(实例化)的对象,用Destroy(毁灭)进行销毁。

介绍几个释放代码:

  1. Destroy:主要用于销毁克隆对象,也可以用于场景内的静态物体,但不会自动释放该对象的所有引用。
  2. AssetBundle.Unload(false):释放AssetBundle(资源束)文件内存镜像。
  3. AssetBundle.Unload(true):释放AssetBundle(资源束)文件内存镜像,同时销毁所以已经Load(下载)的Assets(资源)内存对象。
  4. Resources.UnloadUnusedAssets:用于释放所以没有引用的Asset(资源)对象。

需要注意的是:**
平台为电脑端:加载AssetBundle的时候一切正常。
平台为安卓端:会出现错误。这里写图片描述

认为是加载方法的问题,目前还没找到答案!!
希望各位朋友,留言交流!!

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。