二、资源加载——2、AssetBundle入门

1、AssetBundle的定义和作用
  • AssetBundle(简称AB包)是一个资源压缩包,包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;
  • AssetBundle自身保存着互相的依赖关系;
  • 压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;
  • 把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小;
2、代码打出AB包
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

public class BuildAssetBundles
{ 
    [MenuItem("Assets/Build AssetBundles")]
    public static void CreateAssetBundles()
    {
        Debug.Log("Build......");
        string dir = "AssetBundles";
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

步骤:
(1)把在Asset目录下要打包的资源如图打上要打包标签,默认是None。

image.png

(2)上面的代码已经制作了一个编辑器按钮工具,不需要运行,可直接打包
image.png

(3)在Asset根目录下就会看到自己代码里指定的目录已经打包好了的资源。
结果

3、加载AB包

(1)从本地加载

void Start () {
        //注意路径和包名,要写全。加载时候写的是在Asset文件夹时的资源名字。
        AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/wall.ab");
        //这里的的名字要和Asset文件夹下的名字要保持一致
        GameObject wallPrefab = ab.LoadAsset<GameObject>("walls");
        Instantiate(wallPrefab);
    }

(2)网络方式

IEnumerator Start()
    {
        string url = @"file:///D:\UnityProject\02_TestProject\21_AssetBundle\MyBundleTest\ABTest\AssetBundles\wall.ab";
        UnityWebRequest request = UnityWebRequest.GetAssetBundle(url);
        yield return request.SendWebRequest();
        //方式一
        AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
        //方式二
        //AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        GameObject obj = ab.LoadAsset<GameObject>("walls");
        Instantiate(obj);
    }
4、AssetBundle分组策略总结

(1)逻辑实体分组

  • 一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
  • 一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
  • 所有的场景所共享的部分一个包(包括贴图和模型)
    (2)按照类型分组
  • 所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包
    (3)按照使用分组
    把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
    注意
  • 经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
  • 把需要同时加载的资源放在一个包里面
  • 可以把其他包共享的资源放在一个单独的包里面
  • 把一些需要同时加载的小资源打包成一个包
  • 如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分,例如v1、v2、v3
5、加载顺序
AssetBundle shareMaterial = AssetBundle.LoadFromFile("AssetBundles/shareMaterial.ab");
AssetBundle bag = AssetBundle.LoadFromFile("AssetBundles/bag.ab");
GameObject bagPrefab = bag.LoadAsset<GameObject>("bag");
Instantiate(bagPrefab);

这里bag是依赖于shareMaterial ,在实例化之前要加载好所有的依赖包。

6、资源加载卸载以及AssetBundleManifest的使用
  • (1)从AssetBundleManifest得到所有的资源
//从总的AssetBundle得到所有的资源
AssetBundle mainfestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
AssetBundleManifest mainfest = mainfestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
foreach (string item in mainfest.GetAllAssetBundles())
{
     Debug.Log(item);
}
  • (2)卸载资源方式
    卸载可以减少内存使用,但有可能导致材质贴图等文件丢失。
    所以什么时候去卸载资源
    方法一:
    AssetBundle.Unload(true)-------------卸载所有资源,即使有资源被使用着。强卸载(无视引用的卸载),释放AssetBundle本身的内存,同时回收从AssetBundle抽取的Asset。
    使用场景:
    a:在关切切换、场景切换
    b:资源没被用的时候 调用
    方法二:
    AssetBundle.Unload(false)--------------弱卸载,释放AssetBundle本身的内存,卸载所有没用被使用的资源。
    方法三:
    Resources.UnloadUnusedAssets-----------------全局弱卸载,回收无引用Asset。

  • (3)一个古怪的而不知道怎么解决的问题:
    如果是手动删除了某个ab文件,会有什么情况发生呢?
    首先可以看到文件中是已经删除了wall.ab了的


    1.png

    场景中的ab打包处也没有了wall的应用


    image.png

    但是结果却包含了wall:
    image.png

    为什么呢,因为之前的打包的时候已经包含了wall,却没有卸载掉,一直存在在AssetBundle当中,通过AssetBundleManifest加载就显示出来了。

即使去查看AssetBundles.manifest的内容,这时候也是有wall的。


image.png

那么如何卸载掉呢?

AssetBundle mainfestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
 mainfestAB.Unload(false);
 mainfestAB = null;

在文件夹中直接删除了wall.ab和wall.mainfest,再执行上面代码,原意实现想卸载掉,结果会是什么呢?


image.png

可见并没有卸载掉,在AssetBundles.manifest文件中也依然有wall的内容。

然后我们在IDE中对wall进行Remove unused names.但是再执行

AssetBundle mainfestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
 mainfestAB.Unload(false);
 mainfestAB = null;

这段代码,看下结果,会发现并没有用。
然后有尝试了
mainfestAB.Unload(true);
以及
Resources.UnloadUnusedAssets();
都没能把AssetBundles.manifest文件里的wall去掉。所以通常情况下不要去手动在文件夹中删除ab文件。

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容