这篇总结主要是总结下资源的热更新
前段时间闲来无事,狂撸了下项目的热更新代码,写个笔记总结下吧
打包其实比较简单,主要是项目结构的设计和文件目录的处理比较麻烦。
先设计一个文件结构
--ABResource -- 所有资源打包的主目录
//这些目录是资源的大类
--UI -图集,图片icon资源等
--Module1
--Module2
--Module3
-Animation 动画 animator等资源
--Module1
--Module2
--Module3
--Sound 声音资源
--Module1
--Module2
--Module3
--Model 模型资源
--Map 地图资源,场景相关的超级大图
--Effect 特效类
--Audio 视频类
文件结构的设计直接影响后期的开发效率,打包方式流程其实都知道,但是文件目录结构设计的好,对项目的开发效率提升非常大,所有模块对应的子文件夹名字尽量统一,方便开发的时候使用统一命名存取资源。减少逻辑成本!
打包唯一复杂的地方就是文件夹读取,后缀名的转换
关键是对这个结构体字段的理解 AssetBundleBuild
首先,每一个AssetBundleBuild都代表将要生成的一个ab文件
一个ab文件里面可以关联N个资源,至于多少个资源,由AssetBundleBuild里面的assetNames决定,Unity会根据名字找到当前这个文件夹里面的资源,注意这里面的路径都是Unity Asset开始的相对路径,而C#的Path、Directory这些路径获取工具拿到的都是全局路径,需要自己做转换
AssetBundleBuild里面只有2个字段是比较重要的
AssetBundleBuild.assetBundleName --------这个字段决定了你这份ab文件生成的名字
AssetBundleBuild.assetNames --------这个字段决定了你这份ab文件里面包含了多少个资源
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Linq;
using System;
public class BundelTest {
private static Dictionary<string,AssetBundleBuild> modulAbDic = new Dictionary<string, AssetBundleBuild>();
Dictionary<string,AssetBundle> AllAb = new Dictionary<string, AssetBundle>();
/// <summary>
/// 解析每个模块
/// </summary>
/// <param name="path"></param>
public static void BuildAllBundle(string path)
{
//这里是采用上述的文件结构,所以做的3层遍历,也可以做成递归的方式,让其适用多个层级
// 判断这个路径是否存在
if (Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string realPath = Path.Combine(Application.dataPath,path);
string[] floderList = Directory.GetDirectories(realPath);//这个只能获取当前层级的子层级,不能获取嵌套的
for (int i = 0; i < floderList.Length; i++)
{
string[] fileNames = Directory.GetDirectories(floderList[i]);//这个文件夹下的所有的子文件夹
for (int a = 0; a < fileNames.Length; a++)
{
getBundls(fileNames[a]);//第一层文件夹下面的文件。不包括里面文件夹
}
}
}
/// <summary>
/// 解析模块内的资源
/// </summary>
/// <param name="path"></param>
public static void getBundls(string modulePath)
{
modulePath = modulePath.Replace("\\","/"); //合并的路径都是\\需要转义
string[] flies = Directory.GetFiles(modulePath);
if (flies.Length > 0 )
{
for (int i = 0; i < flies.Length; i++)
{
//处理模块内文件
string assetBundleName = flies[i].Replace(Application.dataPath+"/","");
string ralativePath = getRelativePah(flies[i]);
string _abPath =ralativePath;
string ext = Path.GetExtension(ralativePath);
assetBundleName = assetBundleName.Replace(ext,"")+".ab";
if (ext != ".meta")
{
string name = Path.GetDirectoryName(ralativePath)+"/"+Path.GetFileNameWithoutExtension(ralativePath); //包的名字,这个名字包含了资源的路径。
AssetBundleBuild build = new AssetBundleBuild() ;
if (modulAbDic.ContainsKey(_abPath))
{
if (modulAbDic.TryGetValue(_abPath,out build))
{
build.assetBundleName = assetBundleName;
build.assetNames = new string[]{ralativePath}; --这里是一个资源对应一个build 所以是固定的
modulAbDic[_abPath] = build;
}
}
else
{
build.assetBundleName = assetBundleName;
build.assetNames = new string[]{ralativePath};
modulAbDic.Add(_abPath,build);
}
}
}
}
}
/// <summary>
/// 打包所有资源,每个资源打一份ab,方便进行差异化分析
/// </summary>
public static void BuildAssetBundleForDic()
{
AssetBundleBuild[] builds = modulAbDic.Values.ToArray();
//输出路径可以自行选择,这里是默认输出在桌面
BuildPipeline.BuildAssetBundles(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),"bundle"),builds,BuildAssetBundleOptions.DeterministicAssetBundle ,BuildTarget.StandaloneWindows64);
}
/// <summary>
/// 获取asset下的相对位置
/// </summary>
public static string getRelativePah(string path)
{
string _path = path.Replace("\\","/");
return _path.Replace(Application.dataPath,"Assets");
}
}