1. 调用lua的一个全局的变量
_env = new LuaEnv();
_env.DoString("require helloworld");
_env.Global.Get("str");
很简单,泛型类型里写变量的类型,参数传变量名。
2.访问全局table
众所周知,lua语言里的table功能很强大,结构也和C#里其他的数据结构不一样,访问lua里的table有一个问题就是到底要用什么数据结构去接收它。那么腾讯的程序员已经为我们准备好了4种方法:
(1)将table映射到class
将lua table中的键名与C#中的字段名保持一致,并且都是为public。通过Get接口将class的类型传入,参数填table名,返回的对象便是table映射后的对象
--简单表
gamelanguage={str1="C#",str2="lua",str3="c++"}
public class Language
{
public string str1;
public string str2;
public string str3;
}
_env = new LuaEnv();
_env.DoString("require helloworld");
Language language = _env.Global.Get("gamelanguage");
注意:这里将table映射到Class的过程是值拷贝,如果类比较复杂(其中有复杂类型)需要一层层的映射,代价比较大,比较耗性能。而且,因为是值拷贝所以当C#端的Class和Lua端的table中数据有变化时,另一边不会有变化。
(2)将table映射到Interface(推荐方式)
上面那个是值拷贝,而接下来这个映射到Interface就是一个引用拷贝的过程。
--表
gamelanguage={str1="C#",str2="lua",str3="c++",
TestFunc = function(param1,param2)
print("hello world")
end}
[CSharpCallLua]
public interface ILanguage
{
string str1 { get; set; }
string str2 { get; set; }
string str3 { get; set; }
void TestFunc(string param1,int param2);
}
_env = new LuaEnv();
_env.DoString("require helloworld");
ILanguage language = _env.Global.Get("gamelanguage");
因为接口不包含字段,映射接口实际上是把键值都映射到属性上,属性本质上是方法嘛。注意这里的interface上加上了一个[CSharpCallLua]的标签。有了这个标签以后,我们使用菜单栏上的GenerateCode就会发现在Xlua目录下多了个Gen的目录,下面你会找到命名为XLuaHelloWorldILanguageBridge的一个类,这个类的命名很明显是用XLua加上lua脚本名加上映射的接口类的名字去定义的。
打上这个标签之后,XLua会为我们生成这个接口的实例(接口本身是依赖于实现类来生成对象的嘛),而这个对象里就为我们做了相关引用拷贝的操作,当我们get一个属性,生成代码会get对应的table字段,如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数。
(3)更方便的,映射到Dictionary<>,List<>
不想定义class和interface的话,就用这个,但是无法映射复杂表。
_env.Global.Get> --键和值的类型要和简单表一一对应
_env.Global.Get> --这种方法就只能对应lua里边数组型的table,键值为数字索引
(4) by ref引用拷贝 映射到LuaTable类
这个适合于表复杂 但是使用频率比较低的情况。这种方式好处是不需要生成代码,但也有一些问题,比如慢,比方式2要慢一个数量级,比如没有类型检查。
_env = new LuaEnv();
_env.DoString("require helloworld");
Language language = _env.Global.Get("gamelanguage");
LuaTable lt = _env.Global.Get("sampletable");
int age = lt.Get("age");
string name = lt.Get("name");
LuaFunction func = lt.Get("samplefunction");
func.Call();
3.访问lua中的function
(1)映射到委托
Action act1 =_luaEnv.Global.Get("luaFunc1")
Action act2 =_luaEnv.Global.Get("luaFunc2")
Action act3 =_luaEnv.Global.Get>("luaFunc3")
Action act4 =_luaEnv.Global.Get>("luaFunc4")
注意:1.委托用完之后需要Dispose,否则会报错
2.映射到委托需要加标签[CSharpCallLua],假如是自定义的委托类型,可以在定义上面直接加标签;而内置的比如Action,Func是属于Unity的API,这种就需要去配置文件中加,配置文件就在XLua/Example/ExampleGenConfig.cs里面加。贴一段官方的代码:
//C#静态调用Lua的配置(包括事件的原型),仅可以配delegate,interface
[CSharpCallLua]
public static List CSharpCallLua = new List() {
typeof(Action),
typeof(Func),
typeof(Action),
typeof(Action),
typeof(UnityEngine.Events.UnityAction),
typeof(System.Collections.IEnumerator)
};
上面可以看到,它已经帮我们写好了一部分类型,如果新加入如上述例子代码中第3,4行里的那种类型,就需要手动添加一下。
3.另外,lua函数多返回值的问题,可以看一段官方的Demo:
FDelegate f = luaenv.Global.Get("f");
DClass d_ret;
int f_ret = f(100, "John", out d_ret);//lua的多返回值映射:从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数
Debug.Log("ret.d = {f1=" + d_ret.f1 + ", f2=" + d_ret.f2 + "}, ret=" + f_ret);
其实从左往右映射到C# 这边的返回值、ref out 的参数里
(2)映射的LuaFunction
LuaFunction d_e = luaenv.Global.Get("e");
object[] objs = d_e.Call();
[CSharpCallLua]
总结一下:
1.当我们使用interface来映射lua table时,需要加上此标签为接口生成一个实例代码,它内部帮我们进行了by ref的引用拷贝的相关操作。
2.当我们使用委托来映射Lua function时,需要加上此标签,若是委托类型属于内置API,则需要去配置文件中添加。