Unity | AssetBundle

1. 定义

Unity中的一种特殊资源包格式,用于存储和分发游戏资源。这些资源可以包括模型、纹理、音频文件、预制体、场景等。
AssetBundle允许开发者在游戏运行时动态加载和卸载资源,从而实现灵活的资源管理。

2. 使用场景

1、资源管理
有效管理游戏中的资源,按需下载需要的资源,减少内存消耗,提高游戏加载速度和响应时间。

2、游戏热更新
实现游戏热更新的重要手段。开发者可以在游戏发布后,通过服务器更新AssetBundle,从而更新或替换游戏中的资源,而无需重新发布整个游戏。可以快速修复bug,添加新内容或更新现有内容。

3、DLC(下载内容)
大型游戏通过DLC增加游戏内容。这些DLC通常包含新的关卡、角色、武器等。

3. 使用

1、标记资源

在Unity编辑器中,选择需要打包的资源设置AssetBundle标签

2、创建和构建AssetBundle

编写并运行一个Editor脚本来构建AssetBundle

3、加载AssetBundle

在游戏运行时通过脚本加载AssetBundle

4、使用资源

加载AssetBundle后通过脚本获取并使用资源

5、卸载AssetBundle

使用完AssetBundle后,即使卸载释放内存

4. 程序实现

4.1 编辑器脚本——构建AssetBundle
(1) BuildPipeline

UnityEditor命名空间下的一个静态类,用于创建构建游戏项目的流水线、提供了构建玩家(Player)、资源包(如AssetBundles)和管理构建过程的功能。

使用场景:

自动化构建流:持续继承/持续部署(CI/CD)
跨平台发布:多平台构建;平台特定设置
资源管理:资源包构建;资源优化
版本控制:构建版本管理;热更新支持

常用方法:

BuildPipeline.BuildAssetBundles:构建资源包
参数:
outputPath: 输出路径。
assetBundleOptions: 构建资源包选项,使用“BuildAssetBundleOptions”枚举
target: 目标平台,使用“BuildTarget”枚举
builds: 要构建的 AssetBundle 列表(可选)

方法签名:

public static AssetBundleManifest BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget target);
public static AssetBundleManifest BuildAssetBundles(string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions, BuildTarget target);

.e.g.

string outputPath = "Assets/AssetBundles";
BuildAssetBundleOptions options = BuildAssetBundleOptions.None;
BuildTarget target = BuildTarget.StandaloneWindows;

BuildPipeline.BuildAssetBundles(outputPath, options, target);

BuildPipeline.GetBuildTargetGroup:获取与指定BuildTarget关联的BuildTargetGroup
参数:
platform:目标平台,使用“BuildTarget”枚举

方法签名:

public static BuildTargetGroup GetBuildTargetGroup(BuildTarget platform);

e.g. 

BuildTarget target = BuildTarget.StandaloneWindows;
BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
(2) AssetBundleBuild

UnityEditor命名空间下的一个结构体,用于描述如何打包AssetBundle的一个数据结构。定义了哪些资源文件应该被打包成AssetBundle及该AssetBundle的名称、

包含字段:

·  assetBundleName::string 类型。AssetBundle 的名称。
·  assetBundleVariant:string 类型。AssetBundle 的变体名称(可选)。
·  assetNames:string[] 类型。包含在 AssetBundle 中的资源路径数组。
·  addressableNames:string[] 类型。资源在 AssetBundle 中的可寻址名称(可选)。

using UnityEditor;

public class BuildAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        // 定义一个 AssetBundleBuild 对象
        AssetBundleBuild assetBundleBuild = new AssetBundleBuild();
        
        // 设置 AssetBundle 的名称
        assetBundleBuild.assetBundleName = "examplebundle";
        
        // 设置包含在 AssetBundle 中的资源路径数组
        assetBundleBuild.assetNames = new string[]
        {
            "Assets/ExampleFolder/ExampleAsset1.prefab",
            "Assets/ExampleFolder/ExampleAsset2.prefab"
        };

        // 创建打包列表
        AssetBundleBuild[] buildMap = new AssetBundleBuild[] { assetBundleBuild };

        // 指定输出路径
        string outputPath = "Assets/AssetBundles";

        // 构建 AssetBundles
        BuildPipeline.BuildAssetBundles(outputPath, buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
    }
}
(3) AssetDatabase

Unity编辑器API,用于在编辑器模式下管理和操作资产。提供了一组静态方法,帮助开发者在编辑中查找、加载、保存和操作Unity项目中的资产。
静态类,不包含实例字段,只包含静态方法

使用场景:

查找资源:查找和检索项目中的资源路径、类型和引用;
加载资源:从项目中加载资源进行编辑或查看;
保存和刷新:保存对资源的修改并刷新资源数据库;
创建和删除资源;
导入和导出资源;

常用方法:

AssetDataBase.FindAssets
AssetDataBase.LoadAssetAtPath
AssetDataBase.CreateAsset
AssetDataBase.DeleteAsset
AssetDataBase.ImportAsset
AssetDataBase.SaveAssets
AssetDataBase.Refresh

AssetDataBase.FindAssets:查找符合特定搜索条件的资源
参数:
filter:搜索过滤字符串,如“t”表示搜索所有预制件
searchInFolders:指定要搜索的文件夹路径数组

方法签名:

public static string[] FindAssets(string filter, string[] searchInFolders = null);

e.g.

string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] {"Assets/Prefabs"});
foreach(string guid in guids)
{
    string path = AssetDatabase.GUIDToAssetPath(guid);
    Debug,Log(path);
}

AssetDataBase.LoadAssetAtPath:从指定路径加载资源
参数:
assetPath:资源路径

方法签名:

public static T LoadAssetAtPath<T>(string assetPath) where T: Object;

e.g.

string path = "Asset/Prefab/MyPrefab.prefab";
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);

AssetDataBase.Refresh:刷新资源数据库,使得任何外部修改都能反映到编辑器中

方法签名:

public statuc void Refresh(ImportAssetOptions options = ImportAssetOpttions.Default);

AssetDataBase.CreateAsset:在项目中创建一个新资源
参数:
asset:要创建的资源对象
path:资源的保存路径

方法签名

public static void CreateAsset(Object asset, string path);

e.g.

ScriptableObject obj = ScriptableObject.CreateInstance<MyScriptableObject>();
AssetDatabase.CreateAsset(obj, "Assets/MyScriptableObject.asset");
4.2 运行时脚本——加载和使用AB包
 (1) AssetBundle

用于在运行时加载和管理预先打包的资源

使用场景:

动态加载资源:在游戏运行时从磁盘或网络加载资源,适用于大型游戏或需要频繁更新内容的游戏
内容更新:在不重新发布整个游戏的情况下更新或添加新内容
优化初始安装包:将部分资源大包围Asset Bundles,减小初始安装包的大小
多平台资源管理:为不同平台生成特定的Asset Bundles,从而加载适配的资源

常用方法:

AssetBundle.LoadFromFile:从本地文件系统中同步加载Asset Bundle
参数:
path: AssetBundle 文件的路径。
crc(可选): 用于校验的 CRC 值。
offset(可选): 文件偏移量。
返回值:
加载的 AssetBundle 实例。

方法签名

public static AssetBundle LoadFromFile(string path);
public static AssetBundle LoadFromFile(string path, uint crc);
public static AssetBundle LoadFromFile(string path, uint crc, ulong offset);

e.g.

AssetBundle bundle = AssetBundle.LoadFromFile("Path/to/your/AssetBundle");
if(bundle == null) Debug.Log("Failed to load AssetBundle");

AssetBundle.LoadFromFileAsync:从本地文件系统异步加载
参数:
path: AssetBundle 文件的路径。
crc(可选): 用于校验的 CRC 值。
offset(可选): 文件偏移量。
返回值:
AssetBundleCreateRequest,表示异步加载操作的请求。

方法签名

public static AssetBundleCreateRequest LoadFromFileAsync(string path);
public static AssetBundleCreateRequest LoadFromFileAsync(string path, uint crc);
public static AssetBundleCreateRequest LoadFromFileAsync(string path, uint crc, ulong offset);

Asset.LoadAsset:从Asset Bundle中加载资源
参数:
name:资源名称
T:资源类型

方法签名: 

public T LoadAsset<T>(string name) where T : Object;

e.g. 

GameObject prefab = bundle.LoadAsset<GameObject>("MyPrefab");

Asset.LoadAllAssets:从Asset Bundle加载所有资源

方法签名:

public Object[] LoadAllAssets();

e.g.

Object[] assets = bundle.LoadAllAssets();
foreach (Object asset in assets)
{
    Debug.Log(asset.name);
}

AssetBundle.LoadAssetAsync:从已加载的AssetBundle中异步加载指定类型的资源
参数:
name: 资源名称。
type: 资源类型。
返回值:
AssetBundleRequest,表示异步加载操作的请求。

方法签名

public AssetBundleRequest LoadAssetAsync<T>(string name) where T : UnityEngine.Object;
public AssetBundleRequest LoadAssetAsync(string name, Type type);

AssetBundle.Unload:卸载已经加载的AssetBundle
参数:
unloadAllLoadedObject:是否卸载所有已加载的资源对象

方法签名

public void Unload(bool unloadAllLoadedObjects);
4.3 Code

打包

static void Build(BuildTarget target)
    {
        //创建AssetBundleBuild打包列表
        List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();
        List<string> bundleInfos = new List<string>();                                                      //文件信息列表

        
        //填充列表
        string[] files = Directory.GetFiles(PathUtil.BuildResourcesPath, "*", SearchOption.AllDirectories);    //获取BuildResourcesPath目录下所有文件
        for (int i = 0; i < files.Length; i++)    //根据文件构建AssetBundleBuild对象
        {
            //跳过meta文件
            if (files[i].EndsWith(".meta"))
                continue;

            //处理要打包的文件,根据BundleResources中文件创建AssetBundleBuild对象
            AssetBundleBuild assetBundle = new AssetBundleBuild();    //创建一个新的AssetBundleBuild对象
            string fileName = PathUtil.GetStandardPath(files[i]);     //获取标准化后的文件路径
            Debug.Log("files:" + fileName);    //Log

            string assetName = PathUtil.GetUnityPath(fileName);    //获取相对于Assets文件夹的路径
            assetBundle.assetNames = new string[] { assetName };   //设置assetBundle的资源名称
            string bundleName = fileName.Replace(PathUtil.BuildResourcesPath, "").ToLower();
            assetBundle.assetBundleName = bundleName + ".ab";      //设置assetBundle的名称

            //将AssetBundleBuild对象加入打包列表
            assetBundleBuilds.Add(assetBundle);

            //添加文件和依赖信息
            List<string> dependenceInfo = GetDependence(assetName);
            string bundleInfo = assetName + "|" + bundleName + ".ab";

            if (dependenceInfo.Count > 0)
                bundleInfo = bundleInfo + "|" + string.Join("|", dependenceInfo);

            bundleInfos.Add(bundleInfo);
        }
        

        //检查并初始化输出文件夹
        if (Directory.Exists(PathUtil.BundleOutPath))
            Directory.Delete(PathUtil.BundleOutPath, true);
        Directory.CreateDirectory(PathUtil.BundleOutPath);

        //构建AssetBundles
        BuildPipeline.BuildAssetBundles(PathUtil.BundleOutPath, assetBundleBuilds.ToArray(), BuildAssetBundleOptions.None, target);

        File.WriteAllLines(PathUtil.BundleOutPath + "/" + AppConst.FileListName, bundleInfos);

        AssetDatabase.Refresh();
    }
static List<string> GetDependence(string curFile)
    {
        List<string> dependence = new List<string>();
        string[] files = AssetDatabase.GetDependencies(curFile);
        dependence = files.Where(file => !file.EndsWith(".cs") && !file.Equals(curFile)).ToList();
        return dependence;
    }

 加载

public class ResourceManager : MonoBehaviour
{
    internal class BundleInfo
    {
        public string AssetsName;   //资源名称
        public string BundleName;   //资源所在的AB包的名称
        public List<string> Dependences;    //资源的依赖项列表
    }

    //存放Bundle信息的管理字典
    private Dictionary<string, BundleInfo> m_BundleInfos = new Dictionary<string, BundleInfo>();


    private void LoadAsset(string assetName, Action<Object> action)
    {
        if (AppConst.GameMode == GameMode.EditorMode)
            EditorLoadAsset(assetName, action);
        else
            StartCoroutine(LoadBundleAsync(assetName, action));
    }

   // 编辑器模式加载资源
    void EditorLoadAsset(string assetName, Action<Object> actioin = null)
    {
        //Log
        Debug.LogFormat("Editor Mode Load Resource : {0}", assetName);

        Object obj = UnityEditor.AssetDatabase.LoadAssetAtPath(assetName, typeof(Object));
        if (obj == null)
            Debug.LogError("Asset name is not exist" + assetName);

        actioin?.Invoke(obj);
    }

    // 递归异步加载资源
    IEnumerator LoadBundleAsync(string assetName, Action<Object> action = null)
    {
        string bundleName = m_BundleInfos[assetName].BundleName;
        string bundlePath = Path.Combine(PathUtil.BundleResourcePath, bundleName);
        List<string> dependences = m_BundleInfos[assetName].Dependences;
        if (dependences != null && dependences.Count > 0)
        {
            for (int i = 0; i < dependences.Count; i++)
            {
                yield return LoadBundleAsync(dependences[i]);
            }
        }

        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
        yield return request;

        AssetBundleRequest bundleRequest = request.assetBundle.LoadAssetAsync(assetName);
        yield return bundleRequest;

        //Log
        Debug.LogFormat("Package Bundle Mode Load Resource : {0}", assetName);

        action?.Invoke(bundleRequest?.asset);
    }

    // 解析版本文件
    public void ParseVersionFile()
    {
        //版本文件路径
        string url = Path.Combine(PathUtil.BundleResourcePath, AppConst.FileListName);
        string[] data = File.ReadAllLines(url);

        //解析文件信息
        for (int i = 0; i < data.Length; i++)
        {
            string[] info = data[i].Split('|');

            BundleInfo bundleinfo = new BundleInfo()
            {
                AssetsName = info[0],
                BundleName = info[1]
            };

            //list特性:本质是数组但可动态扩容
            bundleinfo.Dependences = new List<string>(info.Length - 2);
            for (int j = 2; j < info.Length; j++)
            {
                bundleinfo.Dependences.Add(info[j]);
            }
            m_BundleInfos.Add(bundleinfo.AssetsName, bundleinfo);

            if (info[0].IndexOf("LuaScripts") > 0)
                Manager.Lua.LuaNames.Add(info[0]);
        }
    }

    #region 外部使用加载资源接口
    public void LoadUI(string assetName, Action<Object> action = null)
    {
        LoadAsset(PathUtil.GetUIPath(assetName), action);
    }
    #endregion
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值