lua协程 - 把回调模式的代码流程改成顺序执行流程
像ugui的点击按钮,然后触发相关逻辑,都是回调模式的写法,比如下面代码的ShowAlert调用
public class Test7 : MonoBehaviour { public GameObject m_Alert; public Text m_TxtMsg; public Button m_BtnYes; public Button m_BtnNo; private LuaEnv m_LuaEnv; void Start() { m_LuaEnv = new LuaEnv(); m_LuaEnv.AddLoader((ref string filePath) => { filePath = filePath.Replace('.', '/'); filePath = $"Assets/{filePath}.lua.txt"; var txtAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath); return Encoding.UTF8.GetBytes(txtAsset.text); }); m_LuaEnv.Global.Set("Test7MonoInst", this); m_LuaEnv.DoString("require('Lua.Test7')"); } void OnDestroy() { if (null != m_LuaEnv) m_LuaEnv.Dispose(); } //注意: Test7GenConfig不写, lua在调用该函数时无法识别Action<int> public void ShowAlert(string msg, Action<int> cb) { m_Alert.SetActive(true); m_TxtMsg.text = msg; m_BtnYes.onClick.AddListener(() => { if (null != cb) cb(1); m_BtnYes.onClick.RemoveAllListeners(); m_BtnNo.onClick.RemoveAllListeners(); m_Alert.SetActive(false); }); m_BtnNo.onClick.AddListener(() => { if (null != cb) cb(-1); m_BtnYes.onClick.RemoveAllListeners(); m_BtnNo.onClick.RemoveAllListeners(); m_Alert.SetActive(false); }); } }
下面的是代码Gen配置(一定要写),同时还要生成下代码才行,否则lua代码没法正确执行
public static class Test7GenConfig { [LuaCallCSharp] public static List<Type> LuaCallCsList = new List<Type>() { typeof(Action), //这个默认的不写, 下面的Action<int>会不生效 typeof(Action<int>), }; }
下面的lua代码通过协程将ShowAlert的调用改成顺序执行,而不是通过提供回调函数
function ShowAlert(msg, cb) Test7MonoInst:ShowAlert(msg, cb) end function SyncWrap(func, msg) local coThread, isMain = coroutine.running() if isMain then error("no in coroutine") return end local cb = function(btn) --点击按钮时, 唤醒暂停在yield处的代码(1) coroutine.resume(coThread, btn) end func(msg, cb) local resumeParam = coroutine.yield() --此处暂停(1),等待按钮点击时,调用resume唤醒 local btn = resumeParam return btn end local coFunc = function() local btn = SyncWrap(ShowAlert, "确定要退出吗?") if 1 == btn then print("点击了Yes") elseif -1 == btn then print("点击了No") end end local coThread = coroutine.create(coFunc) coroutine.resume(coThread) --执行到第1个yield处
SyncWrap更通用的写法
function SyncWrap(func, ...) local coThread, isMain = coroutine.running() if isMain then error("no in coroutine") return end local cb = function(btn) --点击按钮时, 唤醒暂停在yield处的代码(1) local flag, coReturn = coroutine.resume(coThread, btn) end local funcParams = { ... } table.insert(funcParams, cb) func(unpack(funcParams)) local resumeParams = { coroutine.yield() } --此处暂停(1), 等待按钮点击时,调用resume唤醒 local rets = unpack(resumeParam) return rets end

浙公网安备 33010602011771号