前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity AssetBundle

Unity AssetBundle

作者头像
全栈程序员站长
发布2022-09-12 12:01:04
1.2K0
发布2022-09-12 12:01:04
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

#AssetBundle作用原理 把资源导出成一种叫做AssetBundle的文件,然后打包后可以在Unity程序运行的时候再加载回来用。 AssetBundle是采取某一种压缩方式压缩成的资源文件。节省存储空间,控制游戏包的大小,实现游戏的热更新。

在这里插入图片描述
在这里插入图片描述

AssetBundle文件分类

AssetBundle文件可以分为两类:序列化文件(serialized file)和资源文件(resource files)。 serialized file:资源被打碎放在一个对象中,最后统一被写进一个单独的文件(只有一个)。 resource files:某些二进制资源(图片、声音)被单独保存,方便快速加载。

AssetBundle分组策略

Ab分组策略:

  1. 逻辑实体分组 1)一个UI界面 或 所有UI界面一个包(界面里的贴图和布局信息一个包) 2)一个角色 或 所有角色一个包(这个角色里面的模型和动画一个包) 3)所有的场景所共享的部分一个包(包括贴图和模型)
  2. 按照类型分组 所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包
  3. 按照使用分组 1)把在某一时间需要同时加载的所有资源打成一个包。可以按照关卡或场景划分,一个关卡或场景所需要的所有资源包括角色、贴图、声音等打成一个包 2)把被其他包所共享的资源放在一个单独的包里面 3)把经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
  4. 版本更新分组 如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分,如v1/v2/v3.unity3d
在这里插入图片描述
在这里插入图片描述

BuileAssetBundles

AssetBundle使用相关API:BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64); 结合Unity Editor使用如下:

代码语言:javascript
复制
#if UNITY_EDITOR
using UnityEditor;
using System.IO;

public class BulidAssetBundle
{
    //编辑器扩展,在菜单栏Assets下生成Build AssetBundles菜单
    [MenuItem("Assets/Build AssetBundles")]

    //进行资源打包
    static void BuildAllAssetBundles()
    {
       
        string dir = "AssetBundle";   //使用相对路径保存,文件夹AssetBundle在为工程目录下
        if (Directory.Exists(dir) == false)  //打包之前要保证文件夹存在,不存在的话会报错
        {
            Directory.CreateDirectory(dir);
        }

        //BuildPipeline是UnityEditor中用于打包的类,其中的BuildAssetBundle用于AssetBundle打包
        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);  
        //dir:存储的路径
        //BuildAssetBundleOptions:表示压缩式的算法
        //BuildTarget: 表示用于什么平台
    }

    /*关于BuildAssetBundleOptions的算法选择*/
    //BuildAssetBundleOptions.None:LZMA压缩,压缩包小,但加载时间长。下载之前需要整体解压。下载完成后,包会使用LZ4重新压缩保存于本地,从而在使用资源的时候不需要整体解压。
    //BuildAssetBundleOptions.ChunkBasedCompression:LZ4压缩,压缩率没LZMA高,但可以加载指定资源而不用全解压。一般使用LZ4压缩,占存小,却几乎可以跟不压缩的加载速度相媲美。
    //BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包占存大,加载快

}
#endif

LoadAssetBundles

Ab包的加载主要有四种方式:

  1. AssetBundle.LoadFromMemory和AssetBundle.LoadFromMemoryAsync //内存加载
  2. AssetBundle.LoadFromFile和AssetBundle.LoadFromFileAsync //本地文件加载
  3. WWW.LoadFromCacheOrDownload //服务器和本地都可加载,不推荐
  4. UnityWebRequest //服务器加载
代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking; //UnityWebRequest

public class LoadAssetBundle : MonoBehaviour
{
    IEnumerator Load()  //定义一个加载ab包的协程
    {
        string path = @"AssetBundles/xxx.unity3d";
        string url = @"http://localhost/AssetBundles/xxx.unity3d"; 


        /*第一种加载AB的方式,同步内存加载,AssetBundle.LoadFromMemory*/
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //直接加载AB包
        AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path)); //同步加载二进制文件
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }

        /*第一种加载AB的方式,异步内存加载,AssetBundle.LoadFromMemoryAsync*/
        //间接获取请求
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); //异步加载二进制文件
        //等待请求完成
        yield return request; 
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //获取AB对象
        AssetBundle ab = request.assetBundle;
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }


        /*第二种加载AB的方式,同步本地文件加载,AssetBundle.LoadFromFile*/
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //直接加载AB包
        AssetBundle ab = AssetBundle.LoadFromFile(path); //同步加载本地文件
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }
       
        /*第二种加载AB的方式,异步本地文件加载,AssetBundle.LoadFromFileAsync*/
        //间接获取请求
        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path); //异步加载本地文件
        //等待请求完成
        yield return request; 
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //获取AB对象
        AssetBundle ab = request.assetBundle;
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }
       

        /*第三种加载AB的方式,服务器和本地都可加载,WWW.LoadFromCacheOrDownload*/
        while (Caching.ready == false)
            yield return null;
        //获取www请求
        WWW www = WWW.LoadFromCacheOrDownload(url, 1);
        yield return www;
        if( !string.IsNullOrEmpty(www.error) )
        {
            Debug.Log(www.error);
         yield break;
        }
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //直接加载AB包
        AssetBundle ab = www.assetBundle; 
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }
       

        /*第四种加载AB的方式,服务器加载 ,UnityWebRequest*/
        //获取服务器请求
        UnityWebRequest request = UnityWebRequest.GetAssetBundle(url);
        //等待请求发送完
        yield return request.SendWebRequest();
        //卸载加载缓存数据,如果有某个系统来管理加载好的数据就不需要
        AssetBundle.UnloadAllAssetBundles(true);
        //从DownloadHandlerAssetBundle获取request,得到AB对象
        AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
        AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
        //加载资源对象
        //Object obj = AssetBundle.LoadAsset<T>(assetName);
        //Object[] objArray = AssetBundle.LoadAllAssets();
        GameObject obj = ab.LoadAsset<GameObject>("assetname");
        GameObject[] objs= ab.LoadAllAssets();
        //实例化对象
        Instantiate(obj); 
        foreach(Object o in objs)
        {
            Instantiate(o);
        }

    } //协程

}

DealDependent by Manifests

通过加载Manifests文件可以处理资源的依赖。

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking; //UnityWebRequest

public class Manifest : MonoBehaviour
{
    IEnumerator Manifests()  //定义一个处理资源依赖的协程
    {
        AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath); //加载Ab资源
        AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); //通过加载到的Ab资源对象获得Manifest资源
        
        string[] assets  = manifest.GetAllAssetBundles() //获取Manifests中的所有AssetBundle的名字
        //传递所有Manifest中所有AssetBundle的包的名称,通过迭代器加载所有包
        foreach(string asset in assets)
        {
            AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, asset) ); //Path.Combine(path1, path2)作用是合并两个路径字符串
        }
        
        string[] dependencies = manifest.GetAllDependencies("assetBundle"); //通过获得的Manifest资源对象获得assetBundle包的所有依赖包的名字
        //传递当前包需要依赖包的名称,通过迭代器加载依赖的所有包
        foreach(string dependency in dependencies)
        {
            AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency) ); //Path.Combine(path1, path2)作用是合并两个路径字符串
        }
    }
}

UnloadAssetBundles

卸载AssetBundle主要是为了减少内存占用,但有可能导致依赖丢失。

  1. AssetBundle.Unload(true):卸载所有资源,即使有资源被使用着,并且卸载内存中已加载的资源。 PS:一般在关卡切换、场景切换时候调用。
  2. AssetBundle.Unload(false):卸载所有没用被使用的资源,但会保留内存中已加载的资源。如果重新创建该方法卸载的对象,内存会存相同的资源,造成内存泄漏。

关于资源的其他卸载方式: 场景对象(GameObject):这类物件可通过Destroy函数进行销毁;

资源对象(Resources),除了Prefab以外,资源文件还可以通过两种方式来卸载: 1)通过Resources.UnloadAsset卸载指定的资源,CPU开销小; 2)通过Resources.UnloadUnusedAssets一次性卸载所有未被引用的资源,CPU开销大;需要注意被静态变量引用的资源,调用该方法并不会被卸载,在Profiler中能够看到其引用情况。

WWW对象:调用对象的Dispose函数或将其置为null即可; WebStream:在卸载WWW对象以及对应的AssetBundle对象后,这部分内存即会被引擎自动卸载; SerializedFile:卸载AssetBundle后,这部分内存会被引擎自动卸载;

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking; //UnityWebRequest

public class UnloadAssetBundle : MonoBehaviour
{
    IEnumerator Unload()  //定义一个卸载ab包的协程
    {
        //此处根据加载ab包的方式进行相应的卸载
    }

}

文件校验(CRC、MD5、SHA1)

CRC、MD5、SHA1都是通过对数据进行计算,来生成一个校验值,该校验值用来校验数据的完整性。 Unity在加载Ab包之后,会通过计算生成一个校验值,去和传递过来的校验值进行比对,从而判断数据是否完整。 三种校验算法的不同点:

  1. 算法不同。CRC采用多项式除法,MD5和SHA1使用的是替换、轮转等方法;
  2. 校验值的长度不同。CRC校验位的长度跟其多项式有关系,一般为16位或32位,MD5是16个字节(128位),SHA1是20个字节(160位);
  3. 校验值的称呼不同。CRC一般叫做CRC值;MD5和SHA1一般叫做哈希值或散列值(Hash);
  4. 安全性不同。这里的安全性是指检错的能力,即数据的错误能通过校验位检测出来。CRC的安全性跟多项式有很大关系,相对于MD5和SHA1要弱很多;MD5的安全性很高,SHA1的安全性最高。
  5. 效率不同,CRC的计算效率很高;MD5和SHA1比较慢。
  6. 用途不同。CRC一般用作通信数据的校验;MD5和SHA1用于安全(Security)领域,比如文件校验、数字签名等。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/149607.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • AssetBundle文件分类
  • AssetBundle分组策略
  • BuileAssetBundles
  • LoadAssetBundles
  • DealDependent by Manifests
  • UnloadAssetBundles
  • 文件校验(CRC、MD5、SHA1)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档