AssetBundle
什么是AssetBundle?
AssetBundle实际上是一个资源管理包。AssetBundle 包含了两个部分:数据头以及数据段。数据头内包含了 AssetBundle 的元数据信息,比如它的标识符、压缩类型、manifest 等等。这里的 manifest 是一个以 Object 名称作为键的查找表,用以指定 AssetBundle 中给定 Object 的位置。数据段内包含了序列化 Asset 生成的原始数据,内容会依据压缩算法变化。
AssetBundle 具有如下优点:
- 可以按需加载和释放 Asset 。
- 自带压缩算法,可以按需定制,减少包体容量。
- 自带版本更新内容,可以进行增量更新。
- 内部包含了对 Object 的引用关系。
第一种是在磁盘上的实际文件,就像一个容器,一个文件夹,可以包含其他文件(模型,纹理,预制,音频,甚至整个场景)。没有后缀名称的AssetBundle文件,这个文件是包含了所有的依赖关系的配置文件,加载AssetBundle就是加载的这个文件,有后缀名称的manifest文件,只是用来做本地依赖关系和增量打包的时候用的。
第二种是运行时加载的AssetBundle对象,包含添加到AssetBundle中的所有资产的路径映射,及资产的对象。
UnityWebRequestAssetBundle获取AssetBundle
public void LoadResource(string resName, string filePath)
{
StartCoroutine(LoadResourceCorotine(resName, filePath));
}
IEnumerator LoadResourceCorotine(string resName, string filePath)
{
AssetBundle ab = null;
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(@"http://localhost/AssetBundles/" + filePath);
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
}
else
{
ab = DownloadHandlerAssetBundle.GetContent(request);
//ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
}
if (ab == null)
{
yield break;
}
//同步加载
//GameObject gameObject = ab.LoadAsset<GameObject>(resName);
//异步加载
AssetBundleRequest abRequest = ab.LoadAssetAsync<GameObject>("Cube");
yield return abRequest;
GameObject ob = abRequest.asset as GameObject;
Instantiate(ob);
// 卸载所有的资源
ab.Unload(true);
}
UnityWebRequest获取文本文件,并写入到固定目录
IEnumerator LoadResourceCorotine()
{
UnityWebRequest request = UnityWebRequest.Get(@"http://localhost/fish.lua.txt");
yield return request.SendWebRequest();
string str = request.downloadHandler.text;
File.WriteAllText(@"D:\BaiduNetdiskDownload\xLua_unity\XluaProjects\XluaProjects\PlayerGamePackage\fish.lua.txt", str);
UnityWebRequest request1 = UnityWebRequest.Get(@"http://localhost/fishDispose.lua.txt");
yield return request1.SendWebRequest();
string str1 = request1.downloadHandler.text;
File.WriteAllText(@"D:\BaiduNetdiskDownload\xLua_unity\XluaProjects\XluaProjects\PlayerGamePackage\fishDispose.lua.txt", str1);
}
一、AssetBundle的加载
AssetBundle.LoadFromFile 从磁盘上的文件同步加载AssetBundle
AssetBundle.LoadFromFileAsync 从磁盘上的文件异步加载AssetBundle
函数支持任何压缩类型的包。在lzma压缩的情况下,数据将被解压缩到内存中。可以直接从磁盘读取未压缩和块压缩(chunkcompressed,也就是LZ4)的包。
AssetBundle.LoadFromMemory 从内存同步创建AssetBundle
AssetBundle.LoadFromMemoryAsync 从内存异步创建AssetBundle
使用此方法从字节数组创建AssetBundle。当您使用加密下载数据并需要从未加密的字节创建AssetBundle时,这非常有用。
AssetBundle.LoadFromStream 从托管流同步加载AssetBundle
AssetBundle.LoadFromStreamAsync 从托管流异步加载AssetBundle
函数支持任何压缩类型的包。在lzma压缩的情况下,数据将被解压缩到内存中。可以直接从磁盘读取未压缩和块压缩(chunkcompressed,也就是LZ4)的包。
在加载AssetBundle或捆绑包中的任何资产时,请勿释放Stream对象。它的寿命应该比AssetBundle长。这意味着在调用AssetBundle.Unload之后处理Stream对象。
LZ4算法是“基于块”的,因此当对象从一个LZ4压缩包加载时,仅用于该对象的相应块会被解压。
即使AssetBundle的其他块未解压缩,解压缩单个块允许使用包含的资产。
UnityWebRequestAssetBundle.GetAssetBundle 创建UnityWebRequest,优化用于通过HTTP GET下载Unity资产包
二、Asset的加载
AssetBundle.LoadAsset 从资源包中加载指定的资源
AssetBundle.LoadAssetAsync 从资源包中异步加载资源
AssetBundle.LoadAllAsset 加载当前资源包中所有的资源
AssetBundle.LoadAllAssetAsync 异步加载当前资源包中所有的资源
三、Asset的卸载
AssetBundle.Unload
卸载捆绑包中的所有资产,卸载释放与包内对象关联的所有内存。
AssetBundle.Unload(false) 仅仅销毁AssetBundle对象包含的资源,任何从此包中加载的实际对象保持不变。当然,也将无法从此AssetBundle包中加载任何其他对象。
AssetBundle.Unload(true) 销毁AssetBundle对象包含的资源,同时销毁从此包中加载的资源对象,即会释放AssetBundle.LoadAsset等加载的资源对象。如果场景中有游戏对象引用这些资源,则对它们的引用都会丢失。
Resources.UnloadAssets 释放指定的Asset
Resources.UnloadUnusedAssets 释放没有引用的Asset
AssetBundle的粒度
即每个AssetBundle包含多少资源
打包策略
- 将公共依赖的资源打包到一个公共AssetBundle中,独立的资源打包到一个AssetBundle中
- 将相同类型的资源(Shader、Atlas、Prefab、Material、Scene、动画、声音、特效等)打包成一个AssetBundle
- 地图、Monster、Npc、角色、坐骑、神翼等根据配置进行打包
- 根据资源间的引用关系,去除重复的资源
去除重复的资源
对于没有被指定打包的外部资源,如果多个ab包依赖了它,打包时该资源就会被多次打包进依赖它的ab包中,造成冗余。
解决方案:
建立了三个对应关系的字典:
Dictionary<string, Bundle> m_BundleDic = new Dictionary<string, Bundle>();
Dictionary<string, Asset> m_AssetDic = new Dictionary<string, Asset>();
Dictionary<string, string> m_AssetMapBundleDic = new Dictionary<string, string>();
m_BundleDic:维护了BundleName-Bundle对象对应关系的字典,其中Bundle对象中,维护了当前Bundle中所有的资源列表AssetList。
m_AssetDic:维护了AssetName-Asset对象对应关系的字典
m_AssetMapBundleDic:维护了AssetName-BundleName对应关系的字典
具体操作步骤:
1. 创建一个HashSet,确保所有的资源Asset在Bundle中是唯一的,不产生冗余。
1. 遍历m_BundleDic中每一个Bundle对象的AssetList;
2. 如果不在HashSet中,把Asset加入到HashSet中,否则,执行删除冗余操作;
3. 如果HashSet已经存在相同的Asset时,通过m_AssetMapBundleDic字典获得当前Asset对应的BundleName;
4. 如果当前Asset对应的BundleName在m_BundleDic中,表示多个ab包依赖了这个Asset,从对应的Bundle的AssetList中移除这个Asset。
5.如果当前Asset对应的BundleName不在m_BundleDic中,表示虽然多个ab包依赖了这个Asset,但是其中有一些并不需要打到ab包中,这时,需要把对应的Bundle从m_AssetMapBundleDic中移除。