AssetBundle打包

一.简单的打包实现(打包游戏物体)。

1.将需要打包的游戏物体制作成预制体,在预制体的Inspector面板最下方找到AssetBundle选项,在这里设置物体打包后的包名和后缀。名称为None代表不打包。

 

2.添加打包脚本,脚本不需要继承Monobehavior。在菜单栏上添加打包选项。

using System.IO;
using UnityEditor;

public class CreateAssetBundles
{
    //使用一个静态方法进行打包,将这个方法添加到菜单栏
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        //因为打包时不会自动创建路径,所以检验打包路径是否存在,不存在需要先创建打包路径
        string dir = "AssetBundles";
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        //打包
        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

3.打包

 4.在刚才设置的打包文件夹下可以查看是否打包成功

 

 

二.资源的加载

1.添加空物体,挂载一个用于加载资源的脚本

2.在脚本中加载资源

public class LoadFromFileExample : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //加载资源,加载后的内容保存为AssetBundle对象
        AssetBundle assetBundle = AssetBundle.LoadFromFile("AssetBundles/wall.unity3d");
        //取出资源,资源的类型时GameObject,名称是Wall
        GameObject wallPrefab = assetBundle.LoadAsset<GameObject>("Wall");
        //实例化取出的游戏物体
        Instantiate(wallPrefab);
    }

}

三.更多的打包和加载资源的选择

1.打包目录划分:在unity中的Inspector窗口下确定填写打包后包名时可以通过"/"进行目录划分。不同的资源可以指定相同的包名和后缀,也就是同一个包中可以包含多个资源。

2.AssetBundle分组策略:可以采用按照逻辑实体分组、按照类型分组、按照使用分组等分组策略,根据项目的实际需求确定具体的分组策略。通常遵循以下分组原则:

1)把经常更新的资源和不常更新的资源分开,减少包的大小

2)把需要同时加载的资源放在一起,提高加载效率

3)把和其他包共享的资源单独放置,避免重复打包

4)把一些需要同时加载的小资源放在一起,提高加载效率

5)可以通过后缀区分同一个资源的不同版本

3.BuileAssetBundleOptions选项

官方API:

 

 常用选项:

1)BuildAssetHBundleOptions.None:默认使用LZMA算法压缩。

2)BuileAssetBundleOptions.UncompressedAssetBundle:不压缩

3)BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩

LZMA压缩和LZ4压缩:

LZMA压缩比LZ4压缩后的包体积更小,压缩率更高,但是也意味着解压缩的时间更长,加载时间更长。而且LZMA压缩在解压缩时只能整体解压,如果只是想使用压缩文件中的一小部分内容的话会造成资源浪费,因此一般在下载时使用LZMA压缩算法,下载后再使用LZ4算法保存到本地。

4.minifest文件详解

 

 5.加载AssetBundle的其他方式

1)AssetBundle.LoadFromMemoryAsync方法:加载二进制字节数组

异步的方式

    IEnumerator Start()
    {
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes("AssetBundles/wall.unity3d"));
        yield return request;
        AssetBundle ab = request.assetBundle;

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

同步的方式

    void Start()
    {
        AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes("AssetBundles/wall.unity3d"));

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

2)AssetBundle.LoadFromFile方法:直接从文件加载

异步的方式

    IEnumerator Start()
    {
        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync("AssetBundles/wall.unity3d");
        yield return request;
        AssetBundle ab = request.assetBundle;

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

同步的方式

    void Start()
    {
        AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/wall.unity3d");

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

3)WWW.LoadFromCacheOrDownload方法:从服务器或本地缓存加载(即将弃用)

    IEnumerator Start()
    {
        while (!Caching.ready)
        {
            yield return null;
        }

        WWW www = WWW.LoadFromCacheOrDownload(@"file:\\D:\UnityProjects\AssetBundleLearning\AssetBundles\wall.unity3d", 1);
        AssetBundle ab = www.assetBundle;

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

4)UnityWebRequestAssetBundle方法:从服务器加载(UnityWebRequest方法弃用)

    IEnumerator Start()
    {
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri: @"file:\\D:\UnityProjects\AssetBundleLearning\AssetBundles\wall.unity3d");
        yield return request.SendWebRequest();
        AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }
    IEnumerator Start()
    {
        UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri: @"file:\\D:\UnityProjects\AssetBundleLearning\AssetBundles\wall.unity3d");
        yield return request.SendWebRequest();
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;

        GameObject wallPrefab = ab.LoadAsset<GameObject>("Wall");
        Instantiate(wallPrefab);
    }

6.manifest文件的加载

    void Start()
    {
        //加载manifest文件
        AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
        AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //获取所有包名称
        foreach(string name in manifest.GetAllAssetBundles())
        {
            print(name);
        }
    }
    void Start()
    {
        //加载manifest文件
        AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
        AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

        //获取"wall.unity3d"这个包的所有依赖
        foreach (string name in manifest.GetAllDependencies("wall.unity3d"))
        {
            print(name);
            //加载依赖文件
            AssetBundle.LoadFromFile("AssetBundles/" + name);
        }
    }

7.卸载AssetBundle包

使用AssetBundle.Unload(false)AssetBundle.Unload(true)来卸载资源,参数代表是否将正在使用中的已加载资源一并卸载。但是需要注意的是,如果使用AssetBundle.Unload(false)卸载资源,正在使用中的资源没有被卸载,这些正在使用中的资源就会一直占用内存,为避免内存被一直占用,一般使用AssetBundle.Unload(true)卸载资源,如果一定要使用AssetBundle.Unload(false)卸载资源,可以在合适的时间调用Resources.UnloadUnusedAssets卸载资源或者以非附加的形式加载场景,这样会自动调用Resources.UnloadUnusedAssets卸载资源。

8.文件校验

校验文件通常有CRC、MD5、SHA1三种算法生成校验值,可以从manifest文件中看到,AssetBundle使用的是CRC算法生成校验码。

9.常见问题

1)依赖包重复问题

解决:把共享的资源一起打包/根据使用时间分割包/共享的部分打包到一起

2)图集重复问题

posted @ 2021-02-01 21:30  movin2333  阅读(194)  评论(0编辑  收藏  举报