内容提要
本文介绍xLua框架中C#与Lua的交互方法。加载Lua脚本用LuaEnv的DoString,建议仅创建一个LuaEnv。C#访问Lua全局变量用Global.Get,访问table可映射到class、接口、Dictionary/List或LuaTable,推荐接口或委托方式。Lua调用C#通过CS前缀访问静态成员,支持参数、返回值、可变参数、枚举和事件操作。
延伸解读
LuaEnv生命周期与加载方式
文章强调一个游戏最好只创建一个LuaEnv,因为每个LuaEnv相当于一个独立的Lua虚拟机,多个会增加内存和性能开销。加载脚本时,官方推荐通过DoString执行require 'main',再由main.lua加载其他脚本,这样便于管理依赖和模块化。此外,自定义Loader可以灵活控制脚本来源,但需注意Loader的加载顺序,一旦某个Loader成功加载,后续Loader将不再尝试。
C#访问Lua table的四种方式对比
文章介绍了四种映射table的方法:映射到class/struct、接口、Dictionary/List和LuaTable。映射到class是值拷贝,修改不会同步,且复杂类开销大;映射到接口需要[CSharpCallLua]和public,性能较好;Dictionary/List要求键值类型一致,更轻量;LuaTable最慢且无类型检查,不推荐。选择时应根据数据结构和性能需求权衡。
Lua调用C#的注意事项
Lua通过CS前缀访问C#静态成员,成员方法需用冒号调用。参数处理上,ref和普通参数算输入,out不算;返回值按顺序对应C#的返回值、out和ref。可变参数可直接在Lua中传入多个值。枚举可通过__CastFrom从整数或字符串转换。事件操作使用加减号添加或移除回调,需注意回调函数的生命周期。
Q&A
xLua中如何加载并执行Lua脚本?
使用LuaEnv的DoString方法执行Lua代码,可以传入字符串、TextAsset或通过require加载。建议整个游戏只创建一个LuaEnv,并采用官方推荐的方式:只执行一次DoString("require 'main'"),然后在main.lua中加载其他脚本。
C#如何访问Lua中的全局变量?
先加载Lua脚本,然后通过LuaEnv.Global.Get<T>获取变量,例如:int g_int = env.Global.Get<int>("g_int"); 支持基本类型、class、接口、Dictionary/List和LuaTable等。
C#访问Lua table有哪几种方式?推荐使用哪种?
四种方式:映射到普通class/struct、映射到接口、映射到Dictionary/List、映射到LuaTable。推荐使用接口或委托方式,因为性能好且类型安全。映射到class是值拷贝,修改不会同步;映射到LuaTable较慢且无类型检查,不推荐。
C#如何调用Lua中的全局函数?
推荐使用delegate映射,需要声明带有[CSharpCallLua]的public委托,然后通过env.Global.Get<委托类型>获取。支持返回值、多返回值(使用out参数)等。也可以使用LuaFunction,但不推荐。
Lua中如何调用C#的静态成员和实例成员?
使用CS前缀访问静态成员,例如CS.UnityEngine.Time.deltaTime。实例成员通过对象访问,成员方法使用冒号调用,例如testobj:DMFunc()。
Lua调用C#方法时参数和返回值如何处理?
参数:C#普通参数和ref参数算输入形参,out不算,按从左到右对应Lua实参。返回值:C#返回值、out、ref都算返回值,按从左到右对应Lua多返回值。
Lua中如何处理C#的可变参数和枚举?
可变参数:直接传入多个参数,例如testobj:VariableParamsFunc(5, 'hello', 'john')。枚举:像静态属性一样访问,如CS.Tutorial.TestEnum.E1,也支持__CastFrom方法从整数或字符串转换。
Lua中如何给C#事件添加或移除回调?
使用+-号操作事件,例如testobj:TestEvent('+', lua_event_callback)添加回调,testobj:TestEvent('-', lua_event_callback)移除回调。