##《Lua热更新》发布说明:
++++“Lua热更新”开始了,立钻哥哥终于开始此部分的探索了。
++++作为游戏发布迭代的重要技术:Lua热更新在网络游戏迭代更新中非常重要,特别是对于AppStore这样的平台,我们只需要定期更新主App,原则上可以随时灵活更新我们的以Lua热更新框架为基础的代码。
++++当然,作为一项新引入的技术,我们通常是以【快速入门】=>【基础夯实】=>【中级进阶】=>【高级实战】=>【立钻哥哥带您学Lua热更新】等几个阶段进行探索。
##《Lua热更新》目录:
#第一篇:Lua快速入门篇
#第二篇:Lua基础夯实篇
#第三篇:Lua中级进阶篇
#第四篇:Lua高级实战篇
#第五篇:立钻哥哥带您学Lua热更新
++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818
++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502
++++Lua快速入门篇(基础概述):https://blog.csdn.net/VRunSoftYanlz/article/details/81041359
#第一篇:Lua快速入门篇
++++第一章:Lua基础概述
++++第二章:xLua教程
++++第三章:Lua基础拓展
++++第四章:立钻哥哥带您学Lua热更新
++第二章:xLua教程
++++https://github.com/Tencent/xLua
++++xLua为Unity、.Net、Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用。
++++2.1、xLua教程
++++2.2、xLua的配置
++++2.3、热补丁操作指南
++++2.4、XLua增加删除第三方lua库
++++2.5、xLua API
++++2.6、生成引擎二次开发指南
++++2.7、xLua常见问题
++++2.8、xLua示例参考
++++2.9、xLua拓展总结
++++2.10、立钻哥哥带您学xLua
++2.9、xLua拓展总结
++++立钻哥哥:xLua是Unity的一个插件:Tencent/xLua(腾讯GitHub开源)。
++++C#下Lua编程支持:xLua为Unity、.Net、Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些代码可以方便的和C#相互调用。
++++VS中的Lua插件:babelua。
++2.9.1、ExampleGenConfig.cs(lua中使用到C#库的配置)
++++【xLua的配置:静态列表】:有时我们无法直接给一个类型打标签,比如系统api,没源码的库,或者实例化的泛化类型,这是可以在一个静态类里声明一个静态字段,该字段的类型除[BlackList]和[AdditionalProperties]之外只要实现了IEnumerable
[LuaCallCSharp]
public static List<Type> mymodule_lua_call_cs_list = new List<Type>(){
typeof(GameObject),
typeof(Dictionary<string, int>),
};
++++立钻哥哥:这个字段需要放到静态类中,建议放到Editor目录。
++++ExampleGenConfig.cs(xLua-master\Assets\XLua\Examples\ExampleGenConfig.cs)
//立钻哥哥:lua中使用到C#库的配置
using System.Collections.Generic;
using System;
using UnityEngine;
using XLua;
public static class ExampleGenConfig{
//立钻哥哥:lua中要使用到C#库的配置,比如C#标准库,或者Unity API,第三方库
[LuaCallCSharp]
public static List<Type> LuaCallCSharp = new List<Type>(){
typeof(System.Object),
typeof(UnityEngine.Object),
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Quaternion),
typeof(Color),
typeof(Ray),
typeof(Bounds),
typeof(Ray2D),
typeof(Time),
typeof(GameObject),
typeof(Component),
typeof(Behaviour),
typeof(Transform),
typeof(Resources),
typeof(TextAsset),
typeof(Keyframe),
typeof(AnimationCurve),
typeof(AnimationClip),
typeof(MonoBehaviour),
typeof(ParticleSystem),
typeof(SkinnedMeshRenderer),
typeof(Renderer),
typeof(WWW),
typeof(Light),
typeof(Mathf),
typeof(System.Collection.Generic.List<int>),
typeof(Action<string>),
typeof(UnityEngine.Debug),
}; //立钻哥哥:public static List
//立钻哥哥:C #静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface
[CSharpCallLua]
public static List<Type> CSharpCallLua = new List<Type>(){
typeof(Action),
typeof(Func<double, double, double>),
typeof(Action<string>),
typeof(Action<double>),
typeof(UnityEngine.Events.UnityAction),
typeof(System.Collections.IEnumerator),
}; //立钻哥哥:public static List
//立钻哥哥:黑名单
[BlackList]
public static List<List<string>> BlackList = new List<List<string>>(){
new List<string>(){ “System.Xml.XmlNodeList”, “ItemOf” },
new List<string>(){ “UnityEngine.WWW”, “movie” },
#if UNITY_WEBGL
new List<string>(){ “UnityEngine.WWW”, “threadPriority” },
#endif
new List<string>(){ “UnityEngine.Texture2D”, “alphaIsTransparency” },
new List<string>(){ “UnityEngine.Security”, “GetChainOfTrustVaue” },
new List<string>(){ “UnityEngine.CanvasRenderer”, “onRequestRebuild” },
new List<string>(){ “UnityEngine.Light”, “areaSize”},
}; //立钻哥哥:public static List> BlackList = new List
>(){}
} //立钻哥哥:public static class ExampleGenConfig{}
++2.9.2、LuaBehaviour.cs(立钻哥哥:非常重要)
//立钻哥哥:非常重要(\Assets\XLua\Examples\02_U3DScripting\LuaBehaviour.cs)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using XLua;
using System;
[System.Serializable]
public class Injection{
public string name;
public GameObject value;
} //立钻哥哥:public class Injecton{}
[LuaCallCSharp]
public class LuaBehaviour : MonoBehaviour{
public TextAsset luaScript;
public Injection[] injections;
internal static LuaEnv luaEnv = new LuaEnv(); //all lua behaviour shared one luaenv only
internal static float lastGCTime = 0;
internal const float GCInterval = 1; //1 second
private Action luaStart;
private Action luaUpdate;
private Action luaOnDestroy;
private LuaTable scriptEnv;
void Awake(){
scriptEnv = luaEnv.NewTable();
//立钻哥哥:为每个脚本设置一个独立的环境,可一定程度上防止脚本间全局变量、函数冲突
LuaTable meta = luaEnv.NewTable();
meta.Set(“__index”, luaEnv.Global);
scriptEnv.SetMetaTable(meta);
meta.Dispose();
scriptEnv.Set(“self”, this);
foreach(var injection in injections){
scriptEnv.Set(injection.name, injection.value);
}
luaEnv.DoString(luaScript.text, “LuaBehaviour”, scriptEnv);
Action luaAwake = scriptEnv.Get<Action>(“awake”);
scriptEnv.Get(“start”, out luaStart);
scriptEnv.Get(“update”, out luaUpdate);
scriptEnv.Get(“ondestroy”, out luaOnDestroy);
if(luaAwake != null){
luaAwake();
}
}
//Use this for initialization
void Start(){
if(luaStart != null){
luaStart();
}
}
//Update is called once per frame
void Update(){
if(luaUpdate != null){
luaUpdate();
}
if(Time.time - LuaBehaviour.lastGCTime > GCInterval){
luaEnv.Tick();
LuaBehaviour.lastGCTime = Time.time;
}
}
void OnDestroy(){
if(luaOnDestroy != null){
luaOnDestroy();
}
luaOnDestroy = null;
luaUpdate = null;
luaStart = null;
scriptEnv.Dispose();
Injections = null;
}
} //立钻哥哥:public class LuaBehaviour : MonoBehaviour{}
++2.9.3、LuaEnv(all lua hehaviour shared one luaenv only)
++++立钻哥哥:可以利用一个LuaMananger来管理全局唯一的LuaEnv。
++++internal static LuaEnv lueEnv = new LuaEnv();
++2.9.4、LuaTable(表)
++++private LuaTable scriptEnv;
++++scriptEnv = luaEnv.NewTable();
++++scrptEnv.Set(“self”, this);
++++luaEnv.DoString(luaScript.text, “LuaBehaviour”, scriptEnv);
++2.9.6、获取生命周期函数(Awake()、Start()、Update()、OnDestroy()等)
++++private Action luaState;
++++private Action luaUpdate;
++++private Action luaOnDestroy;
++++Action luaAwake = scriptEnv.Get<Action>(“awake”);
++++scriptEnv.Get(“start”, out luaStart); //等同:luaStart = scriptEnv.Get
++++scriptEnv.Get(“update”, out luaUpdate);
++++scriptEnv.Get(“ondestroy”, out luaOnDestroy);
++2.9.7、热更新流程
++++立钻哥哥:热更新流程:
--【第一步:游戏运行】(检测资源,进行对比更新)
----游戏要更新了,就打包,放到服务器目录下。
----客户端运行的时候,先下载服务器的校验文件(对比本地文件的md5码)。
----有更新,就下载这些文件替换本地文件。
--【第二步:加载资源,开始游戏的主逻辑】
++2.9.8、创建校验文件
++++立钻哥哥:创建校验文件(包括资源和lua等信息),供热更新下载。
//立钻哥哥:创建校验文件(AssetBundleEditor.cs)
public class AssetBundleEditor{
//立钻哥哥:打包
[MenuItem(“AssetBundle/Build AssetBundles”)]
static void BuildAllAssetBundle(){
string outPath = PathUtil.GetAssetBundleOutPath();
BuildPipeline.BuildAssetBundler(outPath, 0, BuildTarget.StandaloneWindows64);
}
//立钻哥哥:创建校验文件
[MenuItem(“Tools/Create Files”)]
static void CreateFiles(){
string outPath = PathUtil.GetAssetBundleOutPath(); //StreamingAssets/Windows
string filePath = outPath + “/files.txt”; //校验文件的路径
if(File.Exists(filePath)){
File.Delete(filePath);
}
//遍历这个文件夹下面的所有文件
List<string> fileList = new List<string>();
listFiles(new DirectoryInfo(outPath), ref fileList);
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
StreamWriter sw = new StreamWriter(fs);
for(int i = 0; i < fileList.Count; i++){
string file = fileList[i];
string ext = Path.GetExtension(file); //立钻哥哥:获取后缀
if(ext.EndsWith(“.meta”)){
continue; //立钻哥哥:不包括Unity的垃圾配置.meta
}
//生成这个文件对应的md5值
string md5 = getFileMd5(file);
string value = file.Replace(outPath + “/”, string.Empty); //立钻哥哥:仅取文件名
sw.WriteLine(value + “|” + md5); //写入到文件
}
sw.Close();
fs.Close(); //立钻哥哥:记得释放
}
//立钻哥哥:遍历文件夹下的所有文件
static void listFiles(FileSystemInfo fileSystemInfo, ref List<string> fileList){
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] infos = directoryInfo.GetFileSystemInfos(); //获取所有的文件系统
foreach(var info in infos){
FileInfo fileInfo = info as FileInfo;
if(fileInfo != null){
fileList.Add(fileInfo.FullName.Replace(“\\”, “/”)); //如果是文件
}else{
listFiles(info, fileList); //立钻哥哥:递归调用读取文件夹下所有文件
}
}
}
//立钻哥哥:获取文件的md5值
static void getFileMd5(string filePath){
FileStream fs = new FileStream(filePath, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(fs);
fs.Close();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < result.Length; i++){
sb.Append(result[i].ToString(“x2”));
}
return sb.ToString();
}
} //立钻哥哥:public class AssetBundleEditor{}
++2.9.9、GameInit功能完善
++++立钻哥哥:GameInit.cs功能完善
//立钻哥哥:更新资源
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Text;
//立钻哥哥:这个脚本是最先执行的
public class GameInit : MonoBehaviour{
private string downloadPath; //立钻哥哥:不要在此赋值(仅声明,Awake赋值)
void Awake(){
downloadPath = PathUtil.GetAssetBundleOutPath(); //立钻哥哥:赋值在Awake
//检测资源进行对比跟新
StartCoroutine(downloadRes());
//开始游戏的主逻辑
}
//立钻哥哥:检测资源
private IEnumerator downloadRes(){
string url = “http://立钻哥哥:6066/Path/”;
string fileUrl = url + “files.txt”;
WWW www = new WWW(fileUrl);
yield return www;
//进行一些网络检测
if(www.error != null){
Debug.LogError(www.error);
}
//判断本地有没有这个目录
//立钻哥哥:如果发布到手机上:游戏一运行,就把streamingAssets的文件拷贝到persistentDataPath路径下
if(!Directory.Exists(downloadPath)){
Directory.CreateDirectory(downloadPath);
}
//把下载的文件写入本地
File.WriteAllBytes(downloadPath + “/files.txt”, www.bytes);
//读取files里面的内容
string filesText = www.text;
string[] lines = filesText.Split(“\n”);
for(int i = 0; i < lines.Length; i++){
if(string.IsNullOrEmpty(lines[i])){
continue;
}
string[] kv = lines[i].Split(‘|’);
string fileName = kv[0];
//拿到本地的这个文件
string localFile = (downloadPath + “/” + fileName).Trim();
//如果本地文件没有,需要下载了
if(!File.Exists(localFile)){
string dir = Path.GetDirectoryName(localFile);
Directory.CreateDirectory(dir);
//开始网络下载
string tmpUrl = url + fileName;
www = new WWW(tmpUrl);
yield return www;
//进行一些网络的检测
if(www.error != null){
Debug.LogError(www.error);
}
File.WriteAllBytes(localFile, www.bytes);
}else{
//如果文件有,开始比对md5(作用:检测是否需要更新)
string md5 = kv[1];
string localMd5 = getFileMd5(localFile);
if(md5 == localMd5){
//如果md5一样的话,那么就没更新
}else{
//如果不一样的话,说明更新了
File.Delete(localFile); //删除本地原来的旧文件
//下载新文件
string tmpUrl = url + fileName;
www = new WWW(tmpUrl);
yield return www;
//进行一些网络检测
if(www.error != null){
Debug.LogError(www.error);
}
File.WriteAllBytes(localFile, www.bytes);
}
}
}
yield return new WaitForEndOfFrame();
Debug.Log(“立钻哥哥:更新完成,可以开始游戏了!”);
} //立钻哥哥:private IEnumerator downloadRes(){ }
//获取文件的md5值
private string getFileMd5(string filePath){
FileStream fs = new FileStream(filePath, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(fs);
fs.Close();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < result.Length; i++){
sb.Append(result[i].ToString(“x2”));
}
return sb.ToString();
} //立钻哥哥:private string getFileMd5(){}
} //立钻哥哥:public class GameInit:MonoBehaviour{}
//立钻哥哥:加载资源包(AssetBundleLoader.cs)
//加载资源包
public IEnumerator Load(){
www = new WWW(bundlePath);
//AssetBundleCreateRequest abcr = AssetBundle.loadFromFileAsync(bundlePath);
//yield return abcr;
while(!www.isDone){
this.progress = www.progress;
//每一帧来调用一次,更新加载进度
if(lp != null){
lp(bundleName, progress);
}
yield return www;
}
progress = www.progress;
if(progress >= 1f){
//加载完成了
assetLoader = new AssetLoader();
assetLoader.AssetBundle = www.assetBundle;
//每一帧来调用一次,更新加载进度
if(lp != null){
pp(bundleName, progress);
}
if(lc != null){
lc(bundleName);
}
}
} //立钻哥哥:public IEnumerator Load(){}
++2.9.10、dowloadRes4Test()本地模拟测试
++++立钻哥哥:检测资源本机测试
private IEnumerator downloadRes4Test(){
string url = “C:/YanlzLuaServer”;
string fileUrl = url + “files.txt”;
//判断本地没有这个文件
if(!Directory.Exists(downloadPath)){
Directory.CreateDirectory(downloadPath);
}
//读取files里面的内容
string[] lines = File.ReadAllLines(fileUrl);
for(int i = 0; i < lines.Length; i++){
if(string.IsNullOrEmpty(lines[i])){
continue;
}
string[] kv = lines[i].Split(‘|’);
string fileName = kv[0];
//拿到本地的这个文件
string localFile = (downloadPath + “/” + fileName).Trim();
//如果本地文件没有,需要下载
if(!File.Exists(localFile)){
Debug.Log(“立钻哥哥:本地没有 ” + fileName + “ 去服务器下载了”);
string dir = Path.GetDirectoryName(localFile);
Directory.CreateDirectory(dir);
//开始网络下载
string tmpUrl = url + “/” + fileName;
string tmpText = File.ReadAllText(tmpUrl);
File.WriteAllText(localFile, tmpText);
}else{
//如果文件files有,开始比对md5(作用:检测是否需要更新)
string md5 = kv[1];
string localMd5 = getFileMd5(localFile);
if(md5 == localMd5){
//立钻哥哥:如果md5一样的话,就不需要更新
Debug.Log(“立钻哥哥:本地有 ” + fileName + “ 而且不需要更新”);
}else{
Debug.Log(“立钻哥哥:本地有 ”+fileName + “需要更新,去服务器下载”);
//如果不一样的话,需要更新
File.Delete(localFile); //删除本地原来的旧文件
//下载新文件
string tmpUrl = url + “/” + fileName;
string tmpText = File.ReadAllText(tmpUrl);
File.WriteAllText(localFile, tmpText);
}
}
}
yield return new WaitForEndOfFrame();
Debug.Log(“立钻哥哥:更新完成了,可以开始游戏了。”);
} //立钻哥哥:private IEnumerator downloadRes4Test(){}
++2.9.11、热更新LuaManager
++++立钻哥哥:创建UI:【Scene】=>【Canvas】=>【Image】/【Text】
++++lua热更新框架:xLua(Assets/Plugins + Assets/XLua)
++++LuaManager管理所有lua脚本
//立钻哥哥:添加LuaManager
//GameInit.cs
using System.Collections;
using UnityEngine;
public class GameInit : MonoBehaviour{
private string downloadPath;
void Awake(){
downloadPath = PathUtil.GetAssetBundleOutPath();
//检测资源进行比对跟新
StartCoroutine(downloadRes4Test());
//开始游戏的主逻辑
gameObject.AddComponent<AssetBundleManager>();
gameObject.AddComponent<LuaManager>(); //立钻哥哥:添加LuaManager
LuaManager.Instance.DoString(“require ‘MyLuaGameInit’”);
}
} //立钻哥哥:public class GameInit : MonoBehaviour{}
//立钻哥哥:LuaManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XLua;
//立钻哥哥Lua管理
public class LuaManager : MonoBehaviour{
public static LuaManager Instance;
private LuaEnv luaEnv = new LuaEnv();
private void Awake(){
Instance = this;
luaEnv.AddLoader(myCustomLoader); //立钻哥哥:注册自定义loader
}
//立钻哥哥:执行lua代码
public void DoString(string chunk, string chunkName = “chunk”, LuaTable env = null){
luaEnv.DoString(chunk, chunkName, env);
}
//立钻哥哥:调用lua方法
public object[] CallLuaFunction(string luaName, string methodName, params object[] args){
LuaTable table = luaEnv.Global.Get<LuaTable>(luaName);
LuaFunction function = table.Get<LuaFunction>(methodName);
return function.Call(args);
}
Dictionary<string byte[]> dict = new Dictionary<string, byte[]>();
private byte[] myCustomLoader(ref string fileName){
//获取lua所在的目录
string luaPath = PathUtil.GetAssetBundleOutPath() + “/Lua”;
if(dict.ContainKey(fileName)){
return dict[fileName];
}
return processDir(new DirectoryInfo(luaPath), fileName);
}
private byte[] processDir(FileSystemInfo fileSystemInfo, string fileName){
DirectoryInfo directoryInfo = fileSystemInfo as DirectoryInfo;
FileSystemInfo[] files = directoryInfo.GetFileSystemInfo();
foreach(var item in files){
FileInfo file = item as FileInfo;
if(file == null){
processDir(item, fileName); //不是文件,是文件夹的话,递归执行
}else{
string tmpName = item.Name.Split(‘.’)[0]; //仅取文件名,不要后缀
if(item.Extension == “.meta” || tmpName != fileName){
continue;
}
byte[] bytes = File.ReadAllBytes(file.FullName);
dict.Add(fileName, bytes); //思路:利用空间换时间(存入Dictionary)
return bytes;
}
}
return null;
} //立钻哥哥:private byte[] processDir(){}
} //立钻哥哥:public class LuaManager : MonoBehaviour{}
//立钻哥哥:lua文件
//xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是:Resource只支持有限的后缀,放Resources下的lua文件得加上txt后缀。
//但是:lua文件是从热更新下来的,一般不在Resources目录下,所以需要自定义Loader,自定义涉及接口:public delegate byte[] CustomLoader(ref string filepath);
//public void LuaEnv.AddLoader(CustomLoader loader); 通过AddLoader可以注册一个回调,该回调参数是字符串,lua代码里头调用require时,参数将会透传给回调,回调中就可以根据这个参数去加载指定文件。
//MyLuaGameInit.lua.txt
print(‘立钻哥哥’)
++2.9.12、AssetBundleManager.cs
++++立钻哥哥:AB管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//立钻哥哥:AssetBundle管理类
public class AssetBundleManager : MonoBehaviour{
private static AssetBundleManager instance;
//单例模式
public static AssetBundleManager Instance{
get{ return instance; };
}
void Awake(){
instance = this;
//先加载mainfest文件
StartCoroutine(AssetBundleMainfestLoader.Instance.Load());
}
void OnDestroy(){
nameSceneDict.Clear();
Resource.UnloadUnusedAssets();
System.CS.Collect();
}
//场景名 和 场景里面所有包的管理 的映射
Dictionary<string, SceneManager> nameSceneDict = new Dictionary<string, SceneManager>();
//加载资源包
public void LoadAssetBundle(string sceneName, string folderName, LoadProgress lp){
if(!nameSceneDict.ContainKey(sceneName)){
//如果没有这个场景,先创建这个场景,再读取一下
createSceneAssetBundles(sceneName);
}
SceneManager sceneManager = nameSceneDict[sceneName];
//开始加载
sceneManager.LoadAssetBundle(folderName, lp, loadAssetBundleCallback);
}
//创建一个场景对应的包
private void createSceneAssetBundles(string sceneName){
SceneManager scene = new SceneManager(sceneName);
scene.ReadRecord(sceneName); //读取记录文件
nameSceneDict.Add(sceneName, scene);
}
//加载资源的回调
private void loadAssetBundleCallback(string sceneName, string bundleName){
if(nameSceneDict.ContainsKey(sceneName)){
SceneManager sceneManager = nameSceneDict[sceneName];
StartCoroutine(sceneManager.Load(bundleName));
}else{
Debug.Log(“立钻哥哥:不存在这个场景: ” + sceneName);
}
}
//获取完整包名
public string GetBundleName(string sceneName, string folderName){
if(nameSceneDict.ContainsKey(sceneName)){
SceneManager sceneManager = nameSceneDict[sceneName];
return sceneManger.GetBundleName(folderName);
}else{
Debug.Log(“立钻哥哥:不存在这个场景: ” + sceneName);
return null;
}
}
//是否加载了这个包
public bool IsLoading(string sceneName, string folderName){
if(nameSceneDict.ContainsKey(sceneName)){
SceneManager sceneManager = nameSceneDict[sceneName];
return sceneManager.IsLoading(folderName);
}else{
Debug.LoaError(“立钻哥哥:不存在这个场景:” + sceneName);
return false;
}
}
//是否加载完成这个包
public bool IsFinish(string sceneName, string folderName){
if(nameSceneDict.ContainsKey(sceneName)){
SceneManager sceneManager = nameSceneDict[sceneName];
return sceneManager.IsFinish(folderName);
}else{
Debug.Log(“立钻哥哥:不存在这个场景:” + sceneName);
return false;
}
}
} //立钻哥哥:public class AssetBundleManager : MonoBehaviour{}
++2.9.13、AssetUtil.cs
++++立钻哥哥:工具类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//加载进度
public delegate void LoadProgress(string bundleName, float progress);
//加载完成时候的调用
public delegate void LoadComplete(string bundleName);
//加载assetbundle的回调
public delegate void LoadAssetBundleCallBack(string sceneName, string bundleName);
public class AssetUtil{
} //立钻哥哥:public class AssetUtil{}
++2.9.14、SceneManager:LoadAssetBundle()
++++立钻哥哥:场景管理器
//加载资源包
public void LoadAssetBundle(string folderName, LoadProgress lp, LoadAssetBundleCallback labcb){
if(folderBundleDict.ContainsKey(folderName)){
string bundleName = folderBundleDict[folderName]; //获取包名
sceneAssetBundles.LoadAssetBundle(bundName, lp, labcb);
}else{
Debug.Log(“立钻哥哥:找不到这个文件夹:” + folderName + “ 对应的包”);
}
}
++2.9.15、OneSceneAssetBundles:LoadAssetBundle()
++++立钻哥哥:加载资源包
//加载资源包
public void LoadAssetBundle(string bundleName, LoadProgress lp, LoadAssetBundleCallback labcb){
//如果这个包已经被加载了,就提示
if(nameBundleDict.ContainsKey(bundleName)){
Debug.Log(“立钻哥哥:此包已经加载了: ” + bundleName);
return;
}else{
//没有被加载
AssetBundleRelation assetBundleRelation = new AssetBundleRelation(bundleName, lp);
nameBundleDic.Add(bundleName, assetBundleRelation); //保存到字典
//StartCoroutine(“Load”, bundleName);
//开始加载
labcb(sceneName, bundleName);
}
}
//加载包
public IEnumerator Load(string bundleName){
while(!AssetBundleManifestLoader.Instance.Finish){
yield return null;
}
AssetBundleRelation assetBundleRelation = nameBundleDict[bundleName];
//先获取这个包的所有依赖关系
string[] dependenceBundles = AssetBundleManifestLoader.Instance.GetDependencies(bundleName);
//添加他的依赖关系
foreach(var dependencebundleName in dependenceBundles){
assetBundleRelation.AddDependence(dependenceBundleName);
//加载这个包的所有依赖关系
yield return LoadDependence(dependencebundleName, bundleName, assetBundleRelation.LoadProgress);
}
//开始加载这个包
yield return assetBundleRelation.Load()
}
//加载依赖的包
private IEnumerator LoadDependence(string bundleName, string referenceBundleName, LoadProgress lp){
if(nameBundleDict.ContainsKey(bundleName)){
//已经加载过 就直接添加他的被依赖关系
AssetBundleRelation assetBundleRelation = nameBundleDict[bundleName];
//添加这个包的被依赖关系
assetBundleRelation.AddReference(referenceBundleName);
}else{
//没有加载过 就创建一个新的
AssetBundleRelation assetBundleRelation = new AssetBundleRelation(bundleName, lp);
//添加这个包的被依赖关系
assetBundleRelation.AddReference(referenceBundleName);
nameBundleDict.Add(bundleName, assetBundleRelation); //保存到字典
}
} //立钻哥哥:private IEumerator LoadDependence(){}
++2.9.16、AssetBundleRelation
//立钻哥哥:构造函数
public AssetBundleRelation(string bundleName, LoadProgress lp){
this.bundleName = bundleName;
this.lp = lp;
this.finish = false;
assetBundleLoder = new AssetBundleLoader(onLoadComplete, lp, bundleName);
dependenceBundleList = new List<string>();
referenceBundleList = new List<string>();
}
++2.9.17、AssetBundleLoader
private AssetLoader assetLoader; //包里的资源
private WWW www; //WWW对象
private string bundleName; //包名
private string bundlePath; //包的路径
private float progress; //进度
private LoadProgress lp; //加载进度回调
private LoadComplete lc; //加载完成回调
//立钻哥哥:构造函数
public AssetBundleLoader(LoadComplete lc, LoadProgress lp, string bundleName){
this.lc = lc;
this.lp = lp;
this.bundleName = bundleName;
this.progress = 0f;
//TODO
this.bundlePath = PathUtil.GetWWWPath() + “/” + bundleName;
this.www = null;
this.assetLoader = null;
}
//加载资源包
public IEnumerator Load(){
www = new WWW(bundlePath);
//AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(bundlePath);
//yield return abcr;
while(!www.isDone){
this.progress = www.progress;
//每一帧来调用一次,更新加载进度
if(lp != null){
lp(bundleName, progress);
}
yield return www;
}
progress = www.progress;
if(progress >= 1f){
//加载完成了
assetLoader = new AssetLoader();
assetLoader.AssetBundle = www.assetBundle;
//每一帧来调用一次,更新加载进度
if(lp != null){
lp(bundleName, progress);
}
if(lc != null){
lc(bundleName);
}
}
} //立钻哥哥:public IEnumerator Load(){}
++2.9.18、MyLuaGameInit.lua
++++立钻哥哥:lua文件
MyLuaGameInit = {}
local this = MyLuaGameInit
//立钻哥哥:类似C#单例模式的演绎
function MyLuaGameInit : GetInstance()
return this
end
MyLuaGameInit.lp = function(name, process)
print(name, process)
end
function MyLuaGameInit : Init()
CS.AssetBundleManager.Instance.LoadAssetBundle(“main”, “UI”, this.lp);
end
//立钻哥哥:GameInit.cs调用Lua
public class GameInit : MonoBehaviour{
private string downloadPath;
void Awake(){
downloadPath = PathUtil.GetAssetBundleOutPath();
//检测资源进行比对更新
StartCoroutine(downloadRes4Test());
//开始游戏的主逻辑
gameObject.AddComponent<AssetBundleManager>();
gameObject.AddComponent<LuaManager>();
LuaManager.Instance.DoString(“require ‘MyLuaGameInit’”); //执行lua脚本
LuaManager.Instance.CallLuaFunction(“MyLuaGameInit”, “Init”);
}
} //立钻哥哥:public class GameInit : MonoBehaviour{}
++2.9.19、MyLuaGameInit.lua完善
++++立钻哥哥:完整lua脚本
MyLuaGameInit = {}
local this = MyLuaGameInit
function MyLuaGameInit : GetInstance()
return this
end
MyLuaGameInit.lp = function(name, process)
print(name, process)
if process >= 1 then
local prefab = CS.AssetBundleManager.Instance.LoadAsset(“Main”, “UI”, “Canvas”)
print(prefab.name)
local canvas = CS.UnityEngine.GameObject.Instantiate(prefab) //静态方法.(:)
canvas.transform:Find(“txtCont”):GetComponent(typeof(CS.UnityEngine.UI.Text)).text = “立钻哥哥:今日有更新”
end
end
function MyLuaGameInit:Init()
CS.AssetBundleManager.Instance:LoadAssetBundle(“Main”, “UI”, this.lp);
end
++2.9.20、PathUtil.cs(路径相关工具类)
using UnityEngine;
using System.IO;
//立钻哥哥:路径
public class PathUtil{
//获取assetbundle的输出目录
public static string GetAssetBundleOutPath(){
string outPath = getPlatformPath() + “/” + GetPlatformName();
if(!Directory.Exists(outPath)){
Directory.CreateDirectory(outPath);
}
return outPath;
} //立钻哥哥:public static string GetAssetBundleOutPath(){}
//自动获取对应平台的路径
private static string getPlatformPath(){
switch(Application.platform){
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
return Appliction.streamingAssetsPath;
case RuntimePlatform.Android:
return Applictiaon.persistentDataPath;
default:
return null;
}
} //立钻哥哥:private static string getPlatformPath(){}
//立钻哥哥:获取对应平台的名字
public static string GetPlatformName(){
switch(Application.platform){
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
return “Windows”;
case RuntimePlatform.Android:
return “Android”;
default:
return null;
}
} //立钻哥哥:public static string GetPlatformName(){}
} //立钻哥哥:public class PathUtil{}
++立钻哥哥推荐的拓展学习链接(Link_Url):
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818
++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502
++++Lua快速入门篇(基础概述):https://blog.csdn.net/VRunSoftYanlz/article/details/81041359
++++框架知识点:https://blog.csdn.net/VRunSoftYanlz/article/details/80862879
++++游戏框架(UI框架夯实篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80781140
++++游戏框架(初探篇):https://blog.csdn.net/VRunSoftYanlz/article/details/80630325
++++设计模式简单整理:https://blog.csdn.net/vrunsoftyanlz/article/details/79839641
++++U3D小项目参考:https://blog.csdn.net/vrunsoftyanlz/article/details/80141811
++++UML类图:https://blog.csdn.net/vrunsoftyanlz/article/details/80289461
++++Unity知识点0001:https://blog.csdn.net/vrunsoftyanlz/article/details/80302012
++++Unity知识点0008:https://blog.csdn.net/VRunSoftYanlz/article/details/81153606
++++U3D_Shader编程(第一篇:快速入门篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80372071
++++U3D_Shader编程(第二篇:基础夯实篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80372628
++++Unity引擎基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78881685
++++Unity面向组件开发:https://blog.csdn.net/vrunsoftyanlz/article/details/78881752
++++Unity物理系统:https://blog.csdn.net/vrunsoftyanlz/article/details/78881879
++++Unity2D平台开发:https://blog.csdn.net/vrunsoftyanlz/article/details/78882034
++++UGUI基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78884693
++++UGUI进阶:https://blog.csdn.net/vrunsoftyanlz/article/details/78884882
++++UGUI综合:https://blog.csdn.net/vrunsoftyanlz/article/details/78885013
++++Unity动画系统基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78886068
++++Unity动画系统进阶:https://blog.csdn.net/vrunsoftyanlz/article/details/78886198
++++Navigation导航系统:https://blog.csdn.net/vrunsoftyanlz/article/details/78886281
++++Unity特效渲染:https://blog.csdn.net/vrunsoftyanlz/article/details/78886403
++++Unity数据存储:https://blog.csdn.net/vrunsoftyanlz/article/details/79251273
++++Unity中Sqlite数据库:https://blog.csdn.net/vrunsoftyanlz/article/details/79254162
++++WWW类和协程:https://blog.csdn.net/vrunsoftyanlz/article/details/79254559
++++Unity网络:https://blog.csdn.net/vrunsoftyanlz/article/details/79254902
++++C#事件:https://blog.csdn.net/vrunsoftyanlz/article/details/78631267
++++C#委托:https://blog.csdn.net/vrunsoftyanlz/article/details/78631183
++++C#集合:https://blog.csdn.net/vrunsoftyanlz/article/details/78631175
++++C#泛型:https://blog.csdn.net/vrunsoftyanlz/article/details/78631141
++++C#接口:https://blog.csdn.net/vrunsoftyanlz/article/details/78631122
++++C#静态类:https://blog.csdn.net/vrunsoftyanlz/article/details/78630979
++++C#中System.String类:https://blog.csdn.net/vrunsoftyanlz/article/details/78630945
++++C#数据类型:https://blog.csdn.net/vrunsoftyanlz/article/details/78630913
++++Unity3D默认的快捷键:https://blog.csdn.net/vrunsoftyanlz/article/details/78630838
++++游戏相关缩写:https://blog.csdn.net/vrunsoftyanlz/article/details/78630687
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
--_--VRunSoft : lovezuanzuan--_--