讲解xLua例6 Coroutine应该从中学习到什么。可将协程写法分为C#协程lua协程和xLua协程。本文关注的是xLua协程。一.例6 Coroutine代码分析1.1 CoroutineTest.cs用来执行coruntine_test.lua没有业务逻辑using UnityEngine; using XLua; namespace XLuaTest { public class CoroutineTest : MonoBehaviour { LuaEnv luaenv null; // Use this for initialization void Start() { luaenv new LuaEnv(); luaenv.DoString(require coruntine_test); } // Update is called once per frame void Update() { if (luaenv ! null) { luaenv.Tick(); } } void OnDestroy() { luaenv.Dispose(); } } }1.2 coruntine_test.lua业务代码lua侧模拟调用C#协程这里先注释掉一部分代码将demo简化有助于理解这个demo1.cs_coroutine.start相当于c#的StartCoroutine2.coroutine.yield(CS.UnityEngine.WaitForSeconds(1))相当于c#的yield return new WaitForSeconds(1f);local cs_coroutine (require cs_coroutine) local a cs_coroutine.start(function() print(coroutine a started) -- coroutine.yield(cs_coroutine.start(function() -- print(coroutine b stated inside cotoutine a) -- coroutine.yield(CS.UnityEngine.WaitForSeconds(1)) -- print(i am coroutine b) -- end)) --print(coroutine b finish) while true do coroutine.yield(CS.UnityEngine.WaitForSeconds(1)) print(i am coroutine a) end end) -- cs_coroutine.start(function() -- print(stop coroutine a after 5 seconds) -- coroutine.yield(CS.UnityEngine.WaitForSeconds(5)) -- cs_coroutine.stop(a) -- print(coroutine a stoped) -- end)1.3 cs_coroutine.luaLua侧支持协程的module获取脚本组件cs_coroutine_runner用来执行协程方法StartCoroutine和StopCoroutinelocal util require xlua.util local gameobject CS.UnityEngine.GameObject(Coroutine_Runner) CS.UnityEngine.Object.DontDestroyOnLoad(gameobject) local cs_coroutine_runner gameobject:AddComponent(typeof(CS.XLuaTest.Coroutine_Runner)) return { start function(...) return cs_coroutine_runner:StartCoroutine(util.cs_generator(...)) end; stop function(coroutine) cs_coroutine_runner:StopCoroutine(coroutine) end }1.4 Coroutine_Runner.cs空的MonoBehaviour用静态列表导出WaitForSecondsusing UnityEngine; using XLua; using System.Collections.Generic; using System.Collections; using System; namespace XLuaTest { public class Coroutine_Runner : MonoBehaviour { } public static class CoroutineConfig { [LuaCallCSharp] public static ListType LuaCallCSharp { get { return new ListType() { typeof(WaitForSeconds), typeof(WWW) }; } } } }1.5 util.lua协程支持文件local unpack unpack or table.unpack local function async_to_sync(async_func, callback_pos) return function(...) local _co coroutine.running() or error (this function must be run in coroutine) local rets local waiting false local function cb_func(...) if waiting then assert(coroutine.resume(_co, ...)) else rets {...} end end local params {...} table.insert(params, callback_pos or (#params 1), cb_func) async_func(unpack(params)) if rets nil then waiting true rets {coroutine.yield()} end return unpack(rets) end end local function coroutine_call(func) return function(...) local co coroutine.create(func) assert(coroutine.resume(co, ...)) end end local move_end {} local generator_mt { __index { MoveNext function(self) self.Current self.co() if self.Current move_end then self.Current nil return false else return true end end; Reset function(self) self.co coroutine.wrap(self.w_func) end } } local function cs_generator(func, ...) local params {...} local generator setmetatable({ w_func function() func(unpack(params)) return move_end end }, generator_mt) generator:Reset() return generator end local function loadpackage(...) for _, loader in ipairs(package.searchers) do local func loader(...) if type(func) function then return func end end end local function auto_id_map() local hotfix_id_map require hotfix_id_map local org_hotfix xlua.hotfix xlua.hotfix function(cs, field, func) local map_info_of_type hotfix_id_map[typeof(cs):ToString()] if map_info_of_type then if func nil then func false end local tbl (type(field) table) and field or {[field] func} for k, v in pairs(tbl) do local map_info_of_methods map_info_of_type[k] local f type(v) function and v or nil for _, id in ipairs(map_info_of_methods or {}) do CS.XLua.HotfixDelegateBridge.Set(id, f) end --CS.XLua.HotfixDelegateBridge.Set( end xlua.private_accessible(cs) else return org_hotfix(cs, field, func) end end end --和xlua.hotfix的区别是这个可以调用原来的函数 local function hotfix_ex(cs, field, func) assert(type(field) string and type(func) function, invalid argument: #2 string needed, #3 function needed!) local function func_after(...) xlua.hotfix(cs, field, nil) local ret {func(...)} xlua.hotfix(cs, field, func_after) return unpack(ret) end xlua.hotfix(cs, field, func_after) end local function bind(func, obj) return function(...) return func(obj, ...) end end --为了兼容luajitlua53版本直接用|操作符即可 local enum_or_op debug.getmetatable(CS.System.Reflection.BindingFlags.Public).__bor local enum_or_op_ex function(first, ...) for _, e in ipairs({...}) do first enum_or_op(first, e) end return first end -- description: 直接用C#函数创建delegate local function createdelegate(delegate_cls, obj, impl_cls, method_name, parameter_type_list) local flag enum_or_op_ex(CS.System.Reflection.BindingFlags.Public, CS.System.Reflection.BindingFlags.NonPublic, CS.System.Reflection.BindingFlags.Instance, CS.System.Reflection.BindingFlags.Static) local m parameter_type_list and typeof(impl_cls):GetMethod(method_name, flag, nil, parameter_type_list, nil) or typeof(impl_cls):GetMethod(method_name, flag) return CS.System.Delegate.CreateDelegate(typeof(delegate_cls), obj, m) end local function state(csobj, state) local csobj_mt getmetatable(csobj) for k, v in pairs(csobj_mt) do rawset(state, k, v) end local csobj_index, csobj_newindex state.__index, state.__newindex state.__index function(obj, k) return rawget(state, k) or csobj_index(obj, k) end state.__newindex function(obj, k, v) if rawget(state, k) ~ nil then rawset(state, k, v) else csobj_newindex(obj, k, v) end end debug.setmetatable(csobj, state) return state end local function print_func_ref_by_csharp() local registry debug.getregistry() for k, v in pairs(registry) do if type(k) number and type(v) function and registry[v] k then local info debug.getinfo(v) print(string.format(%s:%d, info.short_src, info.linedefined)) end end end return { async_to_sync async_to_sync, coroutine_call coroutine_call, cs_generator cs_generator, loadpackage loadpackage, auto_id_map auto_id_map, hotfix_ex hotfix_ex, bind bind, createdelegate createdelegate, state state, print_func_ref_by_csharp print_func_ref_by_csharp, }二.例6 Coroutine运行展示先打印coroutine a started然后每隔1秒打印i am coroutine a三.例6 Coroutine总结例6 Coroutine应该从中学习到什么1.lua模拟C#的协程写法(比如用StartCoroutine和yield return...)不是一个很简单的事需要一些代码支持(cs_coroutine.lua和util.lua)2.util.lua这种非面向对象table写法阅读时先看return对外提供方法放在return中实现在local function中一定要熟悉和适应(笔者第一个商业xLua项目看到这种写法很不习惯不知道从哪里来的现在知道了可能来自util.lua)3.util.lua中的函数需要熟悉商业xLua项目中有可能lua模拟C#的协程写法不一定用但是去使用util.lua中的函数或者把util.lua放在xLua之外的目录应该知道util.lua不是自研的来自xLua