一次性看懂Lua热更新原理与演示
了解了一下热更新机制。如果没有热更新,客户端代码修改后,用户获取新版客户端的步骤是这样的:下载客户端→等待下载→安装客户端→等待安装→启动游戏→等待加载→玩。
有了热更新之后,用户获取新版客户端的步骤变成了这样:启动游戏→等待热更新→等待加载→玩,省去了自行下载安装包并手动安装的步骤。
热更新是为了让用户获得资源和代码的变更。这里说的代码不是真正的二进制代码,用户不关心代码本身,他想要的是变化之后的业务逻辑,而Lua,就是实现热更新的主要机制。
使用Lua,需要先从GitHub上的xLua仓库下载Plugins文件夹和XLua文件夹,放入Unity项目的Assets目录下,导入成功后,Unity编辑器菜单栏会多出一个XLua选项。
下载插件的网址:(https://github.com/Tencent/xLua/tree/master/Assets)
接下来,我用一个最简单的案例来演示Lua热更新到底是怎么工作的。在Unity场景中创建两个UI按钮和一个UI文本组件,第一个按钮(targetButton)负责执行Lua函数,第二个按钮(reloadButton)负责重新加载Lua脚本,Lua文件的内容非常简单,只有几行:
function OnButtonClick()return "Hello from Lua v1"
end
这个函数不做任何复杂的事情,只是返回一段文本,让场景中的Text组件显示出来。
C#脚本是核心,我把代码贴在下面:
public class LuaButtonHandler : MonoBehaviour
{public Button targetButton;public Button reloadButton;public Text displayText;private LuaEnv luaEnv;private string luaFilePath;private void Start(){luaEnv = new LuaEnv();luaFilePath = Path.Combine(Application.streamingAssetsPath, "test.lua.txt");LoadLuaFile(luaFilePath);targetButton.onClick.AddListener(OnButtonClick);reloadButton.onClick.AddListener(ReloadLua);}void LoadLuaFile(string luaFilePath){string luaScript = File.ReadAllText(luaFilePath);luaEnv.DoString(luaScript);Debug.Log("Lua 文件加载成功: " + luaFilePath);}void ReloadLua(){Debug.Log("开始重载 Lua...");string luaScript = File.ReadAllText(luaFilePath);luaEnv.DoString(luaScript);Debug.Log("Lua 重载成功!新逻辑已生效");if (displayText != null){string oldText = displayText.text;displayText.text = "Lua 已重载!再次点击测试按钮查看变化";// 2秒后恢复原来的文字(或保持提示)StartCoroutine(RestoreDisplayTextAfterDelay(oldText, 2f));}}IEnumerator RestoreDisplayTextAfterDelay(string originalText, float delay){yield return new WaitForSeconds(delay);if (displayText != null && displayText.text == "Lua 已重载!再次点击测试按钮查看变化"){displayText.text = originalText;}}void OnButtonClick(){LuaFunction onClickFunc = luaEnv.Global.Get<LuaFunction>("OnButtonClick");object[] result = onClickFunc.Call();if (displayText != null){displayText.text = result[0] as string;}}void OnDestroy(){// 销毁 Lua 虚拟机,释放资源if (luaEnv != null){luaEnv.Dispose();}}
}
end
整个流程是这样的:在Start方法中,先创建一个LuaEnv环境,这是C#与Lua之间的桥梁,然后用LoadLuaFile读取并执行Lua文件,把里面的函数注册到Lua虚拟机中,targetButton绑定了OnButtonClick事件,每次点击按钮,C#会去Lua虚拟机里找到OnButtonClick这个函数并执行它,拿到返回值后显示在Text组件上,如下图所示。

reloadButton绑定了ReloadLua事件,它的作用是重新读取硬盘上的Lua文件,再次执行一遍,从而覆盖Lua虚拟机中的旧函数。
最精彩的部分来了,点击Unity的Play按钮运行游戏,先点击targetButton,Text会显示Lua文件中的返回值,也就是Hello from Lua v1。保持游戏处于运行状态,不要停止,打开Lua文件,把返回值修改成Hello from Lua v2,运行时热更新成功了,保存文件。回到Unity中运行的游戏窗口,点击reloadButton,控制台会输出重载成功的日志,最后,再次点击targetButton。你会发现,Text显示的内容,变成了你刚刚修改后的文字,如下图所示。

这就是Lua的精髓!让一个正在运行中的游戏,在不停止、不重新编译、不重新打包的情况下,获取到变化后的业务逻辑。
