Unity-AB包
什么是AB包:它是一个存在于硬盘上的文件,可以称为压缩包,这个压缩包可以是一个文件夹。
AB包的作用:将资源放到服务器上,当客户端需要的时候从服务器中获取,程序不需要重新安装。
AB包定义:Unity资源压缩包。
AB包依赖的资源:图片,文本,音频,视频,模型,动画,预制体,场景资源,脚本,可编辑脚本资源。
图片支持的格式:.png,.jpg。
文本支持的格式:.txt,.json,.xml。
音频支持的格式:.mp3,.wav,.ogg。
视频支持的格式:.avi,.mp4。
模型支持的格式:.fbx,.obj。
动画支持的格式:.animationClip(fbx内部动画片段)。
预制体支持的格式:配置文件(包含当前游戏物体所依赖的所有组件信息)。
场景资源支持的格式:配置文件(包含当前场景中所有物体的配置信息)。
脚本支持的格式:C#脚本。
可编辑脚本资源:.asset文件。
压缩包可以使用LZMA和LZ4压缩算法,较少包大小,更快的进行网络传输。
压缩后的资源不能直接使用,需要进行解压。
把一些要下载的内容放到AB包中可以减少安装包的大小。
资源冗余:多个包引用同一个资源但引用的资源没有打入AB包。
颗粒度:颗粒度太大会导致不太容易替换资源,过度消耗存储性能,颗粒度太小会导致降低IO读写速度,影响用户体验。
打包策略
1:可以将资源分的很细进行打包,基于每个资源都打一个AB包。
2:一个模块打一个AB包,可以基于文件夹进行打包。
打出来的文件
AB文件
CRC 资源校验
AssetBundleInfos 当前打出的所有的资源包
其他AB配置文件(一个命名一个AB包)
CRC 资源包校验码,资源包的唯一ID。
Hash 每次生成的资源包都会生成一个哈希值,用于做资源包的对比。
Asset 打入当前AB包中的所有的资源。
注:
1:AB包的路径是小写。
2:不标记AssetBundle是不会打到AB包中,标记相同的AssetBundle将会打到一个AB包中。
3:多个AB包都依赖的资源一定要进行打包。模型A和模型B依赖材质C,模型A和模型B不在同一个AB包内
模型A和模型B进行打包,材质C没有进行打包,会导致模型A的AB包内出现材质C,模型B的AB包内出现材质C,下载的资源将会增大。
模型A和模型B进行打包,材质C单独进行打包,模型A的AB包和模型B的AB包对材质C的AB包产生依赖关系,加载模型A的时候是要加载模型A所在的资源包和材质C所在的资源包,不会导致下载资源增加。
模型A和模型B进行打包,材质C和模型A打到了一个AB包内,模型B所在的AB包会和材质C所在的AB包产生依赖关系,加载模型B的时候是需要加载模型B所有的资源包和材质C所在的资源包,不会导致下载资源增加。
4:要打包的资源是需要设置后缀名的。
具体操作
1:服务器·给资源批量设置名称并打成AB包(要放到Editor文件夹下)
// 批量打包工具
using System.IO;
using UnityEditor;
using UnityEngine;
public class ABCreator : EditorWindow {
[MenuItem("Plugins/资源包打包工具")]
static void Init() {
ABCreator abt = EditorWindow.GetWindow<ABCreator>();
abt.Show();
}
// 输入路径
string inputPath;
// AB包输出路径
string outPutPath;
// 选择的平台类型
BuildTarget selectedTarget;
public void OnGUI() {
// 选择打包输出路径
if (GUILayout.Button("选择输入路径")) {
inputPath = EditorUtility.OpenFolderPanel("选择输入路径", Application.dataPath, "");
}
// 选择打包输出路径
if (GUILayout.Button("选择输出路径")) {
outPutPath = EditorUtility.OpenFolderPanel("选择输出的路径", Application.dataPath, "");
}
// 选择对应的打包平台
selectedTarget = (BuildTarget)EditorGUILayout.EnumPopup(selectedTarget);
// 设置要打包的AB包名称
if (GUILayout.Button("批量设置名称")) {
SetABNames(inputPath);
}
// 资源包打包按钮
if (GUILayout.Button("资源包打包")) {
CreateAB();
}
}
private void SetABNames(string input) {
// 获得当前路径下的所有文件夹
string[] paths = Directory.GetDirectories(input);
foreach (var item in paths) {
SetABNames(item);
// 获得当前路径下的文件
string[] filePaths = Directory.GetFiles(item);
foreach (var data in filePaths) {
if (data.Contains(".meta"))
continue;
// 将路径中的右斜杠替换成左斜杠
var temp = data.Replace(@"\", "/");
// 将Asset文件的绝对路径换成Assets
temp = temp.Replace(Application.dataPath, "Assets");
AssetImporter asset = AssetImporter.GetAtPath(temp);
// ab包的名称为当前资源的路径,但不包含文件名
var abName = temp.Substring(0, temp.LastIndexOf("/"));
asset.assetBundleName = abName + ".ab";
}
}
}
private void CreateAB() {
BuildPipeline.BuildAssetBundles(outPutPath, BuildAssetBundleOptions.None, selectedTarget);
}
}
2:服务器·将打好的AB包放到资源服务器(资源服务和游戏服务器不是同一个服务器)
1:客户端·获取服务器清单文件,(打包自动生成在根目录和根目录同名的文件)清单文件就是每个AB包下载的路径
2:客户端·下载AB包(打包自动生成在根目录和根目录同名的文件),通过短连接,Http get请求
3:客户端·从AB包中解压出我想要的资源文件,清单文件
4:客户端·得到当前所有的资源AB包的下载路径,得到每个资源AB包中的哈希值
5:客户端·对比本机已经下载好的资源和本次要下载的AB包资源的哈希值
6:客户端·下载AB包,通过短连接,Http get请求
// 客户端下载测试
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResourceMgr : MonoBehaviour
{
public string 清单网址;
public string 清单资源文件名;
[ContextMenu("下载")]
public void 下载清单资源包()
{
StartCoroutine(开启协程下载清单资源包());
}
private IEnumerator 开启协程下载清单资源包()
{
WWW www = new WWW(清单网址 + "/" + 清单资源文件名);
yield return www;
if (www.isDone && www.error == null)
{
AssetBundle 清单文件资源包 = www.assetBundle;
AssetBundleManifest 资源包清单文件数据 = 清单文件资源包.LoadAsset<AssetBundleManifest>("assetbundlemanifest");
foreach (var 下载路径 in 资源包清单文件数据.GetAllAssetBundles())
{
Hash128 哈希值 = 资源包清单文件数据.GetAssetBundleHash(下载路径);
yield return StartCoroutine(开始下载指定的资源包(下载路径, 哈希值));
}
}
}
static Dictionary<string, AssetBundle> 资源缓存 = new Dictionary<string, AssetBundle>();
private IEnumerator 开始下载指定的资源包(string 下载的路径,Hash128 比对哈希值)
{
WWW www = WWW.LoadFromCacheOrDownload(清单网址 + "/" +下载的路径, 比对哈希值);
yield return www;
if (www.isDone && www.error == null)
{
AssetBundle 下载的资源AB包 = www.assetBundle;
Debug.LogError("当前获取的资源包名" + 下载的资源AB包.name);
foreach(var 资源路径 in 下载的资源AB包.GetAllAssetNames())
{
资源缓存.Add(资源路径, 下载的资源AB包);
}
}
}
public static T Load<T>(string path) where T:UnityEngine.Object
{
Debug.Log("加载资源的路径" + path);
if (资源缓存.ContainsKey(path))
{
return 资源缓存[path].LoadAsset<T>(path);
}
return null;
}
}
本文来自博客园,作者:坞中客,转载请注明原文链接:https://www.cnblogs.com/wuzhongke/p/16723830.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤