框架开发流程,,,热更新最重要的是Bundle,所以Bundle处理放在最前面,,后面二三阶段是C#与Lua的交互
环境安装
开发工具:Unity、VS、Git、TortoiseGit
导入Xlua:官方下载地址:https://github.com/Tencent/xLua
XLua的目录就是Unity的目录,只需要把Assets下面的Plugins和Xlua文件夹复制进Unity项目中即可
构建Bundle需要做什么?
meta不需要打入bundle包
Bundle Build策略?
打Bundle的工具是编辑器的代码,放到Scripts-Editor中,其他脚本放到Framework中
创建BuildTool脚本,BuildTool必须继承Editor,而非Mono,因为不用打进包里
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
///
/// 构建工具类:
/// 创建了三种构建方法windows android ios。
/// Build方法:从所有路径查找文件,排除meta后,把每个文件名作为被打包资源名和bundle名(当然一个bundle可以打包多个文件),GetDependence获取所有文件的依赖文件,
/// 把这些信息写入到bundleInfos,BuildPipeline.BuildAssetBundles一下,就建好了ab包,然后把所有包的信息写入filelist中
///
public class BuildTool : Editor
{
//如何使用Build呢,直接添加工具栏
[MenuItem("Tools/Build Windows Bundle")]
static void BundleWindowsBuild()
{
Build(BuildTarget.StandaloneWindows);
}
//如何使用Build呢,直接添加工具栏
[MenuItem("Tools/Build Android Bundle")]
static void BundleAndroidBuild()
{
Build(BuildTarget.Android);
}
//如何使用Build呢,直接添加工具栏
[MenuItem("Tools/Build IOS Bundle")]
static void BundleIOSBuild()
{
Build(BuildTarget.iOS);
}
//为了能够构建多平台,需要把目标平台作为参数传入。
static void Build(BuildTarget target)
{
//主要目的是收集这个build信息,需要打哪些文件,需要给bundle包用一个什么样的名字,BuildAssetBundles函数用到这个Build数组
List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();
//第一步搜索出我们这个所有文件的文件名Directory.GetDirectories和Directory.GetFiles对应两种打包策略一个获取文件夹一个获取文件,GetFiles比较简单
//searchPattern通配符,*是默认 https://www.cnblogs.com/ost/archive/2006/08/20/481625.html
string[] files = Directory.GetFiles(PathUtil.BuildResourcesPath, "*", SearchOption.AllDirectories);
//所有文件都找出来了,需要排除调meta文件和json文件
for (int i = 0; i < files.Length; i++)
{
if (files[i].EndsWith(".meta") || files[i].EndsWith(".json"))
{
continue;
}
//创建一个需要build的Bundle
AssetBundleBuild assetBundle = new AssetBundleBuild();
//处理出来的路径斜杠可能不同。需要规范一下
string fileName = PathUtil.GetStandardPath(files[i]);
string assetName = PathUtil.GetUnityPath(fileName);//获取unity相对路径
//一个assetBundle可以打包多个文件,这里只放一个文件
assetBundle.assetNames = new string[] { assetName };//assetBundle是一个相对路径文件名
//创建包名
string bundleName = fileName.Replace(PathUtil.BuildResourcesPath, "").ToLower();
assetBundle.assetBundleName = bundleName + ".ab";//Bundle需要后缀是.ab,,,,,,,,至此,Bundle的信息收集完了,需要放进list
assetBundleBuilds.Add(assetBundle);
}
//为什么不用另一个重载BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform),是因为需要自己去资源设置bundle名打标签,很麻烦
//第二个参数把list转为array数组
//第三个参数是压缩格式,选择默认
//第四个参数是目标平台,先选择win
if(Directory.Exists(PathUtil.BundleOutPath))
{
//判断是否有路径,如果有这个文件夹,就删掉文件,,递归recursive删掉所有文件和子文件。
Directory.Delete(PathUtil.BundleOutPath, true);
}
Directory.CreateDirectory(PathUtil.BundleOutPath);//删除路径后,创建路径
BuildPipeline.BuildAssetBundles(PathUtil.BundleOutPath, assetBundleBuilds.ToArray(), BuildAssetBundleOptions.None, target);
}
}
为什么48行要排除json格式?因为vscode可以通过Settings.json文件添加一下几行代码让vscode识别到.bytes格式的lua文件并且排除.meta文件,但是这个json文件打包成ab包后,解ab包读取过程json读不出来,因此,直接排除掉json文件即可
https://blog.csdn.net/weixin_42264818/article/details/127442751
:::info
{
“files.associations”: {
“.bytes": “lua”
},
“files.exclude”: {
".meta”: true
},
}
:::
创建特定的工具类,用来管理路径PathUtil
///
/// 路径工具类:
/// 1定义了所有用到的路径
/// 2返回标准路径或返回unity下的几个文件夹的相对路径
///
//因为所有路径都要用到,所以写入一个只读变量中,用来后期访问
public class PathUtil
{
//为什么要把Application定义出来,因为每一次访问都需要GC一次,定义出来就访问一次;
public static readonly string AssetPath = Application.dataPath;
//只读的,需要打Bundle的目录
public static readonly string BuildResourcesPath = AssetPath + "/BuildResources/";
//Bundle输出目录
public static readonly string BundleOutPath = Application.streamingAssetsPath;
///
/// 获取Unity的相对路径
///
/// 绝对路径
///
public static string GetUnityPath(string path)
{
if(string.IsNullOrEmpty(path))
{
return string.Empty;
}
//从Assets位置拿到相对目录
return path.Substring(path.IndexOf("Assets"));
}
///
/// 获取标准路径
///
/// 路径
///
public static string GetStandardPath(string path)
{
if (string.IsNullOrEmpty(path))
{
return string.Empty;
}
//先处理空格,在处理反斜杠
return path.Trim().Replace("\\", "/");
}
}
https://blog.csdn.net/Czhenya/article/details/88181930
dataPath :返回程序的数据文件所在的文件夹的路径(只读)。返回路径为相对路径,一般是相对于程序安装目录的位置。不同游戏平台的数据文件保存路径不同。
StreamingAssetsPath: 此属性用于返回数据流的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径。(只读)
PersistentDataPath:返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。对应同一平台,在不同程序中调用此属性时,其返回值是相同的,但是在不同的运行平台下,其返回值会不一样。
temporaryCachePath:此属性用于返回一个临时数据的缓冲目录(只读)。对于同一平台,在不同程序中调用此属性时,其返回值是相同的,但是在不同的运行平台下,其返回值是不一样的。
persistentDataPath和temporaryCachePath的返回值一般是程序所在平台的固定位置,适合程序在运行过程中产生的数据文件。
点击构建Bundle的自定义工具栏按钮,就可以构建Bundle包了
使用Gitee推送现有的版本,,,,在XluaFramework路径下面git,把unity那个文件夹下面的文件拖进git生成的本地仓库xlua-framework,以后开发都用这个进行开发
如果只是加载了ab包,不会把prefab依赖的图片等还原出来,需要处理一下,,意味着所有打了ab包的都需要还原,,如果需要自动加载ab包,需要把依赖包绑定到主ab包作关联
需要使用一个版本文件把Bundle文件的文件信息保存下来。文件信息包括:文件路径名、bundle名、依赖文件列表
public class Test : MonoBehaviour
{
//因为需要异步加载方式,因此改为协程
IEnumerator Start()
{
//资源包异步创建请求。
//AssetBundleCreateRequest用于加载bundle文件返回的东西,,,,,加载bundle只需要.ab文件
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/ui/prefabs/testui.prefab.ab");
yield return request;
//手动加载prefab用到的两个图片的ab包,,,,后面有自动加载依赖ab包的方法,,,如果需要自动加载ab包,需要把依赖包绑定到主ab包作关联
AssetBundleCreateRequest request1 = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/ui/res/menu-background-image.png.ab");
yield return request1;
AssetBundleCreateRequest request2 = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/ui/res/button.png.ab");
yield return request2;
//从一个资源包(AssetBundle)异步加载请求。
//等待AB包加载完成,去加载指定bundle包内的名字的文件,例如xx.prefab
AssetBundleRequest bundleRequest = request.assetBundle.LoadAssetAsync("Assets/BuildResources/UI/Prefabs/TestUI.prefab");
yield return bundleRequest;
//加载完文件,实例化
GameObject go = Instantiate(bundleRequest.asset) as GameObject;
go.transform.SetParent(this.transform);
go.SetActive(true);
go.transform.localPosition = Vector3.zero;
}
}
public class AppConst
{
public const string BundleExtension = ".ab";
public const string FileListName = "filelist.txt";
}
//为了能够构建多平台,需要把目标平台作为参数传入。
static void Build(BuildTarget target)
{
...
//文件信息列表
List<string> bundleInfos = new List<string>();
for (int i = 0; i < files.Length; i++)
{
...
//添加文件和依赖信息
List<string> dependenceInfo = GetDependence(assetName);
//版本信息包括文件路径名、bundle名、依赖文件列表
string bundleInfo = assetName + "|" + bundleName + ".ab";
if (dependenceInfo.Count > 0)
bundleInfo = bundleInfo + "|" + string.Join("|", dependenceInfo);
bundleInfos.Add(bundleInfo);
}
...
//写bundle信息文件
File.WriteAllLines(PathUtil.BundleOutPath + "/" + AppConst.FileListName, bundleInfos);
//创建好文件后,在unity资源库中刷新一下
AssetDatabase.Refresh();
}
///
/// 获取依赖文件列表
///
/// 需要获取依赖的文件
///
static List<string> GetDependence(string curFile)
{
List<string> dependence = new List<string>();
//把这个文件的依赖文件全部或取出来,,会获取脚本文件和自身文件,,因此需要去掉。
string[] files = AssetDatabase.GetDependencies(curFile);
dependence = files.Where(file => !file.EndsWith(".cs") && !file.Equals(curFile)).ToList();
return dependence;
}