Unity3D AssetBundle 浅谈

1、前言
  AssetBundle是Unity中的一种资源包,可以包含了我们用到的几乎所有资源,实现资源的热更。

2、文件格式的类型
  我们打包AssetBundle后,Unity3D会根据文件的后缀名将文件转换为特定的类型对象存储起来,我们后期获取时需要根据这些类型取出打包的数据,这里简单记录下不同后缀文件打包后的类型。

  • 文本格式
    支持后缀:txt、xml;
    打包后的类型:TextAsset,数据保存在TextAsset的text属性中。

  • 二进制格式
    支持后缀:bytes;
    打包后的类型:TextAsset,数据保存在TextAsset的bytes属性中。

  • 预制件格式
    支持后缀:prefab;
    打包后的类型:GameObject,加载后还需要调用Instantiate函数实例化才能使用。

  • 图片格式
    支持后缀:bmp、jpg、png;
    打包后的类型:Texture2D、Sprite。

  • 音乐格式
    支持后缀:aiff、wav、mp3、ogg;
    打包后的类型:AudioClip。

转载链接:https://www.cnblogs.com/hammerc/p/4785394.html

3、打包
  AssetBundle打包要注意资源之间的依赖关系,生成尽量少的bundle数目和尽可能不产生冗余资源。以下示例是以文件夹为一个bundle,并检测依赖资源也按这种方式打包。资源文件夹Resources目录下
 在这里插入图片描述

    [MenuItem("AssetBundle/Window")]
    public static void PackWindow()
    {
        //EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows);
        StartPack(BuildTarget.StandaloneWindows, "Assets/Resources", Application.streamingAssetsPath);
    }

    private static void StartPack(BuildTarget target, string path, string outPath)
    {
        if (!Directory.Exists(path))
            return;

        if (!Directory.Exists(outPath))
            Directory.CreateDirectory(outPath);
        AssetBundleBuild[] builders = GetAllAssetBundleBuild(path);
        BuildPipeline.BuildAssetBundles(outPath, builders, BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DisableWriteTypeTree, target);
        Debug.Log("AssetBundle ok !");
    }

    public static string StandardizedPath(string path)
    {
        return path.Replace("\\", "/");
    }  

    private static AssetBundleBuild[] GetAllAssetBundleBuild(string path)
    {
        Dictionary<string, string> builderDic = new Dictionary<string, string>();
        List<AssetBundleBuild> builders = new List<AssetBundleBuild>();
        GetBuildersInfo(path, builderDic);

        foreach (KeyValuePair<string, string> keyValuePair in builderDic)
        {
            string assetName = keyValuePair.Key;
            string bundleName = keyValuePair.Value + ".ab";

            AssetBundleBuild build = new AssetBundleBuild();
            build.assetBundleName = bundleName.ToLower();
            string[] assets = new string[1];
            assets[0] = assetName;
            build.assetNames = assets;

            builders.Add(build);
        }

        return builders.ToArray();
    }

    private static void GetBuildersInfo(string path, Dictionary<string, string> dic)
    {
        if (string.IsNullOrEmpty(path) || dic == null)
            return;

        string[] dirs = Directory.GetDirectories(path);
        if (dirs != null && dirs.Length > 0)
        {
            for (int i = 0; i < dirs.Length; i++)
            {
                GetBuildersInfo(dirs[i], dic);
            }
        }
        else
        {
            string[] files = Directory.GetFiles(path);
            if (files == null || files.Length == 0)
            {
                Debug.Log("无资源文件夹 " + path);
                return;
            }

            foreach (string file in files)
            {
                string standardlizedFile = StandardizedPath(file);
                if (standardlizedFile.EndsWith(".meta"))
                    continue;
                if (!dic.ContainsKey(standardlizedFile))
                    dic.Add(standardlizedFile, StandardizedPath(path));
                    
				//依赖包处理
                string[] depends = AssetDatabase.GetDependencies(new string[1] { standardlizedFile });
                for (int i = 0; i < depends.Length; i++)
                {
                    string dependAssetName = StandardizedPath(depends[i]);
                    if (!dic.ContainsKey(dependAssetName))
                        dic.Add(depends[i], System.IO.Path.GetDirectoryName(dependAssetName));
                }
            }

        }
    }

打包完成bundle资源如下:
在这里插入图片描述
具体资源怎么打包bundle,每个人都可以有自己的策略,但是对依赖资源要很好的处理,尽量减少冗余资源。
注意MainAsset这个文件,它里面包我们需要的信息后面会用到。

4、加载
  ab包加载主要分为两大类,同步加载和异步加载,同步加载直接获得资源,使用比较方便,但是ab包过大会造成卡顿,异步加载很好的解决了这个问题。以下已同步加载为例,注意在加载ab包时,要先加载它所有的依赖包。

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

public class AssetBundleManager : MonoBehaviour {

    public static AssetBundleManager Instance;

    private Dictionary<string, AssetBundle> assetBundleDic = new Dictionary<string, AssetBundle>();
    private AssetBundleManifest manifest;
    private string manifestName = "StreamingAssets";

    // Use this for initialization
    void Awake()
    {
        if (Instance != null)
            return;

        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    void Start () {
        string path = Application.streamingAssetsPath + "/" + manifestName;
        if (File.Exists(path))
        {
            AssetBundle bundle = AssetBundle.LoadFromFile(path);
            if (bundle)
                manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
    }
	
	// Update is called once per frame
	void Update () {
		
	}

    public GameObject LoadPrefab(string asset)
    {
        return LoadAsset<GameObject>(asset.ToLower());
    }

    private T LoadAsset<T>(string asset) where T : UnityEngine.Object
    {
        try
        {
            T result = null;
            string assetName = System.IO.Path.GetDirectoryName(asset) + ".ab";
            AssetBundle ab = GetContainsAssetBundle(assetName);
            if (null == ab)
                ab = LoadAssetBundleAndDependencies(assetName);
            if (ab != null)
                result = ab.LoadAsset<T>(asset);

            return result;
        }
        catch (System.Exception ex)
        {
            Debug.LogError("AssetBundleManager.LoadAsset is failed!" + asset + " : " + ex.Message);
        }

        return null;
    }

    private AssetBundle GetContainsAssetBundle(string asset)
    {
        if (assetBundleDic.ContainsKey(asset))
            return assetBundleDic[asset];
        return null;
    }

    private AssetBundle LoadAssetBundleAndDependencies(string asset)
    {
        if (manifest == null)
        {
            Debug.LogWarning("AssetBundleManifest loading failed! ");
            return null;
        }
        string[] dependents = manifest.GetDirectDependencies(asset);
        for (int i = 0; i < dependents.Length; i++)
        {
            if (LoadAssetBundleAndDependencies(dependents[i]) == null)
            {
                Debug.LogWarning(asset + " Dependencies " + dependents[i] + " loading failed !");
                return null;
            }
        }

        return LoadAssetBundle(asset);
    }

    private AssetBundle LoadAssetBundle(string asset)
    {
        AssetBundle bundle = GetContainsAssetBundle(asset);
        if (bundle == null)
        {
            string path = Application.streamingAssetsPath + "/" + asset;
            if (File.Exists(path))
            {
                bundle = AssetBundle.LoadFromFile(path);
                assetBundleDic.Add(asset, bundle);
            }
            else
            {
                Debug.LogWarning(asset + " not Exists !");
            }
        }

        return bundle;
    }
}

异步加载大致流程基本相同,这里不再介绍。
ab包卸载自己把握时间

AssetBundle.Unload(false),卸载AB包资源,同时保留内存中已加载的资源; 
AssetBundle.Unload(true),卸载AB包资源,同时卸载内存中已加载的资源,会造成资源的丢失

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值