对于游戏开发人员来说,游戏热更新再熟悉不过了,只要是网络游戏,要使游戏长时间生存下去,都要对游戏进行更新,最常用到的热更新方式就是使用Lua脚本。Lua语言不用经过编译,在代码中读取Lua代码后即可运行,因此常用到的一种热更新方案就是:把要更新的代码逻辑写到一个Lua脚本里面,然后上传到服务器,客户端开始游戏后,先到服务器上比对与客户端已经下载的Lua脚本版本是否一样,如果不一样,就从服务器上下载Lua脚本到客户端本地文件夹中,然后在客户端读取下载后的Lua脚本运行里面的代码即可。
常用的Lua有ToLua、ULua和XLua,其中以ToLua用的居多。当我们在Lua脚本中写热更新的代码逻辑时,会调用引擎中开发人员创建的C#脚本,本文就简单的介绍一下如何ToLua与C#之间的交互。
大家可以到https://github.com/topics/ToLua下载ToLua的框架。把下载好的ToLua框架放到Unity引擎的Assets目录下,在菜单栏会生成新的菜单,如下图:
Assets目录如下图所示(版本不一样,目录结构稍有不同,但主要文件夹结构不会改变):
在Editor/Custom文件夹下有CustomSettings.cs脚本,本脚本的主要作用是注册新的类,以方便在Lua脚本中调用。先在引擎中创建一个C#脚本CSVParse.cs,该脚本的功能是解析csv类型的数据,CSVParse.cs脚本中里面包含了两个静态方法,代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.IO; public class CSVParse { public static List<QuestionModel> CSVParse_QuestionModel(string csvName) { List<string[]> dataArray = new List<string[]>(); List<QuestionModel> questionModels = new List<QuestionModel>(); StreamReader sr = null; try { string file_url = Application.dataPath + "/Resources/Configs/" + csvName; sr = File.OpenText(file_url); } catch { Debug.Log("File is not find"); } string line; while ((line = sr.ReadLine()) != null) { dataArray.Add(line.Split(',')); } for (int i = 1;i < dataArray.Count;i++) { //ID string _id = dataArray[i][0]; //问题类型 QuestionType _questionType = (QuestionType)Enum.Parse(typeof(QuestionType), dataArray[i][1], true); //背景图片 string _bgName = dataArray[i][2]; //声音片断 string _soundName = dataArray[i][3]; //标题文字 string _title = dataArray[i][4]; //所有选项的图片名称 List<string> _imageNames = new List<string>(); string str = dataArray[i][5]; string[] names = str.Split('|'); for (int j = 0;j < names.Length;j++) { _imageNames.Add(names[j]); } //回答类型 AnswerType _answerType = (AnswerType)Enum.Parse(typeof(AnswerType), dataArray[i][6], true); //问题选项 List<string> _answerNames = new List<string>(); str = dataArray[i][7]; string[] strs = str.Split('|'); for (int j = 0;j < strs.Length;j++) { _answerNames.Add(strs[j]); } //结果 string _result = dataArray[i][8]; QuestionModel model = new QuestionModel(_id, _questionType, _bgName, _soundName, _title, _imageNames, _answerType, _answerNames, _result); questionModels.Add(model); } sr.Close(); sr.Dispose(); return questionModels; } public static Scene_Model CSVParse_SceneModel(string csvName) { List<string[]> dataArray = new List<string[]>(); StreamReader sr = null; try { string file_url = Application.dataPath + "/Resources/Configs" + "//" + csvName; sr = File.OpenText(file_url); } catch { Debug.Log("File is not find"); } string line; while ((line = sr.ReadLine()) != null) { dataArray.Add(line.Split(',')); } //视频名字 string _videoName = null; if (dataArray[0][0].Equals("V")) { _videoName= dataArray[0][1]; } //问题组 List<QuestionGroup> _questionGroups = new List<QuestionGroup>(); //Flag组 List<FlagGroup> _flagGroups = new List<FlagGroup>(); for (int i = 1;i < dataArray.Count;i++) { if (dataArray[i][0].Equals("Q")) { string time = dataArray[i][1]; List<string> _questionIDs = new List<string>(); for (int j = 2;j < dataArray[i].Length;j++) { _questionIDs.Add(dataArray[i][j]); } QuestionGroup _questionGroup = new QuestionGroup(time, _questionIDs); _questionGroups.Add(_questionGroup); }else if (dataArray[i][0].Equals("F")) { string _time = dataArray[i][1]; FlagType _flagType = (FlagType)Enum.Parse(typeof(FlagType), dataArray[i][2], true); FlagGroup _flagGroup = new FlagGroup(_time, _flagType); _flagGroups.Add(_flagGroup); } } Scene_Model _sm = new Scene_Model(_videoName, _questionGroups, _flagGroups); sr.Close(); sr.Dispose(); return _sm; } }
(以上代码内容请忽略,主要是看如何在Lua中调用上面的方法)
ToLua需要把C#脚本的类名注册到ToLua框架中,然后在Lua脚本中才能够使用该类以及类里面的成员。打开CustomSettings.cs脚本,在public static BindType[] customTypeList ={}中添加如下代码:
_GT(typeof(CSVParse))
保存脚本后点击Lua/Clear wrap files菜单,清除已存在的所有文件。
然后点击上图中的Generate All,在Source/Generaet目录下,就会生成Lua语言中能识别的类库,该文件是以Wrap为结尾的C#文件。
以下流程是在C#脚本中调用上面的CSVParse.lua脚本,在层级视图中创建空物体Manager,给其添加LuaManager脚本组件,然后再添加Test.cs脚本,脚本内容如下:
void Start() { List<QuestionModel> list = CSVParse.CSVParse_QuestionModel("Q_Config.csv"); Debug.Log(list.Count); }
运行程序后显示如下:
以下流程是在C#中读取Lua脚本,在Assets/Lua文件夹中创建CSVParse.lua脚本,脚本内容如下:
Test = {} local this = Test require('TestMusic') local ui local manager local audio local function this.Awake(object) manager = GameObject.Find('Manager') manager:AddComponent(typeof(AudioSource)) coroutine.start(Voice.PlayRightVoice) end
Test.cs脚本中改为如下代码:
void Start() { LuaManager.Instance.LuaClient.LuaState.DoFile("Test.lua"); LuaManager.Instance.LuaClient.CallFunc("Test.Awake", gameObject); }
运行程序以后,就可以播放音乐了,以上就是本文的大致内容,针对文章中的技术大家可以私聊我,让我一起共同进步吧。