Xlua基础(二) C#调用Lua

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,则需要去配置文件中添加。

你可能感兴趣的:(xlua,lua)