Unity 3D-新版AssetBundle(实战)

在上一篇博客我介绍了Unity新版AssetBundle系统的一些知识点,在这篇博客中,我用一个小小的Demo来实践一下(Demo的开发工具为Unity5.3.5 + VS2015,请注意IDE版本)。

先准备一个Modle,资源结构如下所示

预制体JuShiGuai使用了材质球Mat1,Mat2,而Mat1,Mat2又分别使用了JuShiGuai_01,JuShiGuai_02两个贴图文件。 
 


下面就长话短说直接上代码,具体的用法可以参见上一篇博客

1.设置Modle下的资源的AssetBundleName


Mat1              :  materials/mat1.unity3d
Mat2              :  materials/mat2.unity3d
JuShiGuai_01      :  texture/jushiguai_01.unity3d
JuShiGuai_02      :  texture/jushiguai_02.unity3d
JuShiGuai         :  jushiguai.unity3d


这儿我直接按原有目录设置,具体情况在实际使用中有待商榷

2.编写AssetBundle打包代码


为了方便路径的管理,这儿采用我再 Unity 中管理Tag的方式来管理


创建AssetBundleConfig.cs,管理路径

using UnityEngine;
using System.Collections;

/*****************************************************************************
* @author : zyx
* @date : 2016/11/16 15:15
* @instructions : 设置打包AssetBundle用的的相关路径
*****************************************************************************/
public class AssetBundleConfig : MonoBehaviour {

    //AssetBundle打包后存储的路径
    public static string ASSETBUNDLE_PATH = Application.dataPath + "/StreamingAssets/";

    //资源地址
    public static string APPLICATION_PATH = Application.dataPath + "/";

    //工程根目录地址
    public static string PROJECT_PATH = APPLICATION_PATH.Substring(0, APPLICATION_PATH.Length - 7);

    //AssetBundle打包的后缀名
    public static string SUFFIX = ".assetbundle";
}12345678910111213141516171819202122


2.创建 AssetBundleBuild.cs,打包AssetBundle


这儿我使用了LZ4压缩格式,保证包的大小和加载速度额均衡

using UnityEngine;
using System.Collections;
using UnityEditor;

/*****************************************************************************
* @author : zyx
* @date : 2016/11/16 15:16
* @instructions : AssetBundle打包
*****************************************************************************/
public class AssetBundleBuild : MonoBehaviour {
    [MenuItem("AssetBundle Editor/AssetBundle Build")]
    static void AssetBundlesBuild()
    {
        //注:第一个存放AssetBundle的路径取相对地址
        BuildPipeline.BuildAssetBundles(AssetBundleConfig.ASSETBUNDLE_PATH.Substring(AssetBundleConfig.PROJECT_PATH.Length),
            BuildAssetBundleOptions.DeterministicAssetBundle|BuildAssetBundleOptions.ChunkBasedCompression,
            BuildTarget.StandaloneWindows64
            );
    }
}1234567891011121314151617181920


代码编译后会在Unity工具栏挂载AssetBundle Editor栏,点击菜单栏AssetBundle Build就会自动对所有设置了assetbundleName的代码进行打包


3.编写AssetBundle加载代码

在传统的方法中,我们加载一个资源,总是加载资源的依赖项–>加载资源–>卸载依赖项,但是当一个资源频繁被其他资源依赖,这样无疑会造成性能问题。

一个可行的解决方案是:我们可以把加载好的资源用字典存着,下次如果还需要加载这个依赖项就可以直接从字典里面读取,程序运行结束后在卸载字典中加载的AssetBundle.

当然可能还会有更好的加载方案,比如统计一个资源的被依赖次数和使用频率,然后定义一个时间周期,将不活跃的资源定期销毁

这儿我就采用字典的方案,把加载好的资源用字典存着


创建 AssetBundleLoad.cs


using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/*****************************************************************************
* @author : zyx
* @date : 2016/11/16 15:20
* @instructions : AssetBundle的加载,采用字典存贮依赖项,避免频繁地加载和卸载AssetBundle
*****************************************************************************/
public class AssetBundleLoad : MonoBehaviour
{

    private static AssetBundleManifest manifest = null;
    private static Dictionary<string, AssetBundle> assetBundleDic = new Dictionary<string, AssetBundle>();
    void OnGUI()
    {
        if (GUILayout.Button("Load JushiGuai"))
        {
            StartCoroutine(InstanceAsset("jushiguai"));
        }
    }

    public AssetBundle LoadAssetBundle(string Url)
    {
        if (assetBundleDic.ContainsKey(Url))
            return assetBundleDic[Url];
        if (manifest == null)
        {
            //Debug.Log(AssetBundleConfig.ASSETBUNDLE_PATH);
            AssetBundle manifestAssetBundle = AssetBundle.LoadFromFile(AssetBundleConfig.ASSETBUNDLE_PATH + "StreamingAssets");
            manifest = (AssetBundleManifest)manifestAssetBundle.LoadAsset("AssetBundleManifest");
        }
        if (manifest != null)
        {
            //获取当前加载AssetBundle的所有依赖项的路径
            string[] objectDependUrl = manifest.GetAllDependencies(Url);
            foreach (string tmpUrl in objectDependUrl)
            {
                //通过递归调用加载所有依赖项
                LoadAssetBundle(tmpUrl);
            }
            Debug.Log(AssetBundleConfig.ASSETBUNDLE_PATH + Url);
            assetBundleDic[Url] = AssetBundle.LoadFromFile(AssetBundleConfig.ASSETBUNDLE_PATH + Url);
            return assetBundleDic[Url];
        }
        return null;
    }


    private IEnumerator InstanceAsset(string assetBundleName)
    {
        string assetBundlePath = assetBundleName + AssetBundleConfig.SUFFIX;
        int index = assetBundleName.LastIndexOf('/');
        string realName = assetBundleName.Substring(index + 1, assetBundleName.Length - index - 1);
        yield return LoadAssetBundle(assetBundlePath);
        if (assetBundleDic.ContainsKey(assetBundlePath) && assetBundleDic[assetBundlePath] != null)
        {
            Object tmpObj = assetBundleDic[assetBundlePath].LoadAsset(realName);
            yield return Instantiate(tmpObj);
            assetBundleDic[assetBundlePath].Unload(false);
        }
        yield break;
    }
}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364

最后一张层序运行截图奉上

4.assetbundleName的自动化设置和清除

新版的AssetBundle虽然提出了AssetBundleName这样一个新的方法。但是在实际工程中,如果对于每个资源都手动添加设置Name。一来会十分麻烦,二来容易出错,三来不方便管理。所以在实际项目中,我们需要一个方法对于一些资源进行批量命名。

一个可行的方案就是,在工程中把资源分类的放好,我们直接读取资源的相对路径+名字,设置为它的assetbundleName,这样AssetBundle打包之后就会有和源资源相同的目录层级结构,更便于管理


创建AssetBundleNameEdit.cs动态的设置清除assetbundleName


using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;

/*****************************************************************************
* @author : zyx
* @date : 2016/11/16 16:47
* @instructions : 添加工具栏,一键式添加,移除AssetBundleName
*****************************************************************************/
public class AssetBundleNameEdit : MonoBehaviour
{

    [MenuItem("AssetBundle Editor/SetAssetBundleName")]
    static void SetResourcesAssetBundleName()
    {
        //只读取当前选中的目录,排除子目录
        Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.Assets | SelectionMode.ExcludePrefab);
        //此处添加需要命名的资源后缀名,注意大小写。
        string[] Filtersuffix = new string[] { ".prefab", ".mat", ".dds" };
        if (SelectedAsset.Length == 0) return;
        foreach (Object tmpFolder in SelectedAsset)
        {
            string fullPath = AssetBundleConfig.PROJECT_PATH + AssetDatabase.GetAssetPath(tmpFolder);
            //Debug.Log(fullPath);
            if (Directory.Exists(fullPath))
            {
                DirectoryInfo dir = new DirectoryInfo(fullPath);
                var files = dir.GetFiles("*", SearchOption.AllDirectories);
                for (var i = 0; i < files.Length; ++i)
                {
                    var fileInfo = files[i];
                    //显示进度条
                    EditorUtility.DisplayProgressBar("设置AssetBundleName名称", "正在设置AssetBundleName名称中...", 1.0f * i / files.Length);
                    foreach (string suffix in Filtersuffix)
                    {
                        if (fileInfo.Name.EndsWith(suffix))
                        {
                            string path = fileInfo.FullName.Replace('\\', '/').Substring(AssetBundleConfig.PROJECT_PATH.Length);
                            //资源导入器
                            var importer = AssetImporter.GetAtPath(path);
                            if (importer)
                            {
                                string name = path.Substring(fullPath.Substring(AssetBundleConfig.PROJECT_PATH.Length).Length + 1);
                                importer.assetBundleName = name.Substring(0, name.LastIndexOf('.')) + AssetBundleConfig.SUFFIX;
                            }
                        }
                    }
                }
            }

        }
        //删除所有未使用的assetBundle资产数据库名称
        AssetDatabase.RemoveUnusedAssetBundleNames();
        EditorUtility.ClearProgressBar();
    }


    //输出所有AssetBundleName
    [MenuItem("AssetBundle Editor/GetAllAssetBundleName")]

    static void GetAllAssetBundleName()
    {

        string[] names = AssetDatabase.GetAllAssetBundleNames();

        foreach (var name in names)
        {
            Debug.Log(name);
        }

    }


    [MenuItem("AssetBundle Editor/ClearAssetBundleName")]

    static void ClearResourcesAssetBundleName()
    {
        UnityEngine.Object[] SelectedAsset = Selection.GetFiltered(typeof(Object), SelectionMode.Assets | SelectionMode.ExcludePrefab);
        //此处添加需要清除的资源后缀名,注意大小写。
        string[] Filtersuffix = new string[] { ".prefab", ".mat", ".dds" };
        if (SelectedAsset.Length == 0) return;
        foreach (Object tmpFolder in SelectedAsset)
        {
            string fullPath = AssetBundleConfig.PROJECT_PATH + AssetDatabase.GetAssetPath(tmpFolder);
            if (Directory.Exists(fullPath))
            {
                DirectoryInfo dir = new DirectoryInfo(fullPath);
                var files = dir.GetFiles("*", SearchOption.AllDirectories);
                for (var i = 0; i < files.Length; ++i)
                {
                    var fileInfo = files[i];
                    EditorUtility.DisplayProgressBar("清除AssetBundleName名称", "正在清除AssetBundleName名称中...", 1.0f * i / files.Length);
                    foreach (string suffix in Filtersuffix)
                    {
                        if (fileInfo.Name.EndsWith(suffix))
                        {
                            string path = fileInfo.FullName.Replace('\\', '/').Substring(AssetBundleConfig.PROJECT_PATH.Length);
                            var importer = AssetImporter.GetAtPath(path);
                            if (importer)
                            {
                                importer.assetBundleName = null;
                            }
                        }
                    }
                }
            }
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.RemoveUnusedAssetBundleNames();
    }
}
 

代码编译后会在之前的工具栏AssetBundle Editor下多挂载几个选项,选中某个目录,点击菜单栏选项SetAssetBundleName(ClearAssetBundleName)就会自动对所有选中目录进行assetbundleName的添加(移除)

关于从服务器加载的实现等有空在补上。

最后附上Demo的git地址(Click here!)

注:Demo的开发工具为Unity5.3.5 + VS2015,请注意IDE版本
--------------------- 
作者:zhangyx_Xyz 
来源:CSDN 
原文:https://blog.csdn.net/zhangyx_Xyz/article/details/53194267?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值