• 菜鸟学习


    【由于学习,所以翻译!】

    1.介绍

    LuaInterface 是 Lua 语言和 Microsoft.NET 平台公共语言运行时 (CLR) 之间的集成库。

    非常多语言已经有面向 CLR 编译器和 CLR 实现,已经存在为微软windows、 BSD 操作系统和 Linux 操作系统。

    Lua是一个为扩展应用程序而设计的编程语言,解释运行,非常容易嵌入的库。具体的信息能够參考Lua'sreference manual。

    以下的部分介绍如何编译和安装LuaInterface。第3部分包括了在CLR应用程序中使用它,第4部分介绍Lua脚本中的使用。

    2.安装LuaInterface

    LuaInterface须要Lua解释器来工作。

    Lua5.0的一个解释器已经包括在LuaInterface公布包中,包括Mircrosoft Windows下的LuaInterface二进制文件和.NETCLR(LuaInterface.dll和luanet.dll)。你必须拷贝lua50.exe和lua50.dll到你的PATH目录下,拷贝LuaInterface.dll到你的全局Assembly缓存。LuaInterface使用Compat-5.1,因此拷贝luanet.dll到你的package.cpath下。
    从源代码编译LuaInterface不困难。公布包包括一个用来编译luanet的project文件。其是在Visual Studio .Net 2003下的。用来编译的编译脚本是在Visual Studio 6下的。

    你能够简单的编译全部src/LuaInte得到LuaInterface.dll。

    3.在CLR下使用Lua

    CLR应用程序通过LuaInterface.Lua类来使用Lua解释器。实例化这个类。创建一个新的Lua解释器,不同实例直接全然独立。 Lua类索引创建,读取和改动全部变量,由变量的名字索引,如在以下的演示样例 (索

    引器总是返回一个对象,必须强制转换为正确的类型):
    代码:

    // Start a Lua interpreter
    Lua lua = new Lua();
    // Create global variables "num" and "str"
    lua["num"] = 2;
    lua["str"] = "a string";
    // Create an empty table
    lua.NewTable("tab");
    // Read global variables "num" and "str"
    double num = (double)lua["num"];
    string str = (string)lua["str"];


    DoString和DoFile方法运行Lua脚本。当脚本返回值时,这种方法返回一个数组。如
    代码:

    // Execute a Lua script file
    lua.DoFile("script.lua");
    // Execute chunks of Lua code
    lua.DoString("num=2");
    lua.DoString("str=’a string’");
    // Lua code returning values
    object[] retVals = lua.DoString("return num,str");

    LuaInterface自己主动转换Lua的nil到CLR的null,strings到System.String。numbers到System.Double,booleans到System.Boolean。tables到LuaInterface.LuaTable。functions到LuaInterface.LuaTable,反之亦然。Userdata是一种特殊情况:CLRobjects没有匹配的Lua类型。userdata转换回原类型当传递给CLR时。LuaInterface转换其他userdata到LuaInterface.LuaUserData.
             LuaTable和LuaUserData对象有索引来读取和改动字段,使用字符串或数字进行索引。LuaFunction和LuaUserData对象包括一个Call方法来运行函数。包括參数个数。

    返回值在一个数组中。
             最后。Lua类有一个RegisterFunction函数来注冊CLR函数作为一个全局Lua函数。它的參数包括函数名字、目标函数和表示方法的MethodInfo。如lua.RegisterFunction("foo",obj,obj.GetType().GetMethod("Foo"))注冊了object obj的Foo方法作为foo函数。

    4.lua下使用CLR

            这个部分包括在Lua脚本初始化和使用CLR对象,或通过Lua解释器运行,或在CLR应用程序中运行。以下的全部样例都是Lua语言。


    4.1载入CLR类型和实例化对象

            为了实例化对象,脚本须要类型引用。使用静态字段 static fields、调用静态方法static methods相同也须要类型引用。为了获得类型引用,脚本文件首先须要加

    载一个assembly包括指定类型。通过load_assembly函数。然后使用import_type函数来获得引用。以下的样例显示了如何使用这两个函数:
    代码:

    require"luanet"
    -- Loads the System.Windows.Forms and System.Drawing assemblies
    luanet.load_assembly("System.Windows.Forms")
    luanet.load_assembly("System.Drawing")
    Form = luanet.import_type("System.Windows.Forms.Form")
    Point = luanet.import_type("System.Drawing.Point") -- structure
    -- Loading an enumeration
    StartPosition = luanet.import_type("System.Windows.Forms.FormStartPosition")

    调用实例化对象的类型引用。LuaInterface使用第一个满足參数个数和类型的构造函数,由于有重载构造函数存在,匹配过程会转换数字字符串到数字,数字到字符

    串,假设必要,Lua中的数字參数相同转换到相应CLR数字类型。

    get constructor bysig返回一个给定的类型和构造函数的 signa-ture (为构造函数的形參类型的类型引用) 的构造函数。调用返回构造函数实例化的对象。以下的演示样例演示实例化一个 CLR 对象的不同方法:
    代码:

    -- SomeType is a reference to a type with the following constructors
    -- 1. SomeType(string)
    -- 2. SomeType(int)
    -- 3. SomeType(int,int)
    obj1 = SomeType(2,3) -- instantiates SomeType with constructor 3
    obj2 = SomeType("x") -- instantiates SomeType with constructor 1
    obj3 = SomeType(3) -- instantiates SomeType with constructor 1
    Int32 = import_type("System.Int32")
    -- Gets the SomeType constructor with signature (Int32)
    SomeType_cons2 = get_constructor_bysig(SomeType,Int32)
    obj3 = SomeType_cons2(3) -- instantiates SomeType with constructor 2

    4.2使用字段和方法

            脚本中能够使用CLR对象的字段,语法和从table中索引数据一样。写入字段的数据被转换为了相应字段的类型,赋给Int32字段的数字转换为了Int32.没有被索引的属

    性也像字段一样使用。

            LuaInterface有一个简单的索引一维数组的方式。如arr[3].多维数组须要使用Array类的方法。

            脚本能够调用对象的方法,语法和调用table的方法一样,传递对象的第一个參数。使用‘:’操作符.能够使用Get和Set方法来使用索引属性(usually get PropertyName and set PropertyName).。


    代码:

    -- button1, button2 and form1 are CLR objects
    button1.Text = "OK";
    button2.Text = "Cancel";
    form1.Controls:Add(button1);
    form1.Controls:Add(button2);
    form1:ShowDialog();


            Lua仅仅有按值參数的函数调用,因此当脚本调用一个使用了out或ref參数的方法时,LuaInterface返回这些參数的输出值,和方法的返回值一起。在方法调用中out 參

    数应被省略,例如以下例所看到的:
    代码:

    -- calling int obj::OutMethod1(int,out int,out int)
    retVal,out1,out2 = obj:OutMethod1(inVal)
    -- calling void obj::OutMethod2(int,out int)
    retVal,out1 = obj:OutMethod2(inVal) -- retVal será nil
    -- calling int obj::RefMethod(int,ref int)
    retVal,ref1 = obj:RefMethod(inVal,ref1)


             假设一个方法被重载,第一个匹配參数数目、类型的版本号会被调用。忽略out參数。以下的样例展示了一个脚本怎么调用不同版本号的SomeType的重载SomeMethod方法。
    代码:

    -- Versions of SomeType.SomeMethod:
    -- 1. void SomeMethod(int)
    -- 2. void SomeMethod(string)
    -- 3. void SomeMethod(OtherType)
    -- 4. void SomeMethod(string,OtherType)
    -- 5. void SomeMethod(int,OtherType)
    -- 6. void SomeMethod(int,OtherTypeSubtype)
    -- obj1 is instance of SomeType
    -- obj2 is instance of OtherType
    -- obj3 is instance of OtherTypeSubtype
    obj1:SomeMethod(2) -- version 1
    obj1:SomeMethod(2.5) -- version 1, round down
    obj1:SomeMethod("2") -- version 1, converts to int
    obj1:SomeMethod("x") -- version 2
    obj1:SomeMethod(obj2) -- version 3
    obj1:SomeMethod("x",obj2) -- version 4
    obj1:SomeMethod(2,obj2) -- version 4
    obj1:SomeMethod(2.5,obj2) -- version 4, round down
    obj1:SomeMethod(2,obj3) -- version 4, cast
    -- versions 5 and 6 never get called


            还有函数 get_method_bysig 的情况下一种方法有永远不会调用的版本号。给定一个对象或类型引用和方法签名signature(方法的名称和类型) 该函数将返回与该签名。如以下演示样例所看到的的方法:
    代码:

    -- Versions of SomeType.SomeMethod:
    -- 5. void SomeMethod(int,OtherType)
    -- obj1 is instance of SomeType
    -- obj2 is instance of OtherType
    Int32 = luanet.import_type(’System.Int32’)
    SomeMethod_sig5 = luanet.get_method_bysig(obj1,’SomeMethod’,
    Int32,obj2:GetType())
    SomeMethod_sig5(obj1,2,obj2) -- calls version 5

             假设一个方法或字段名称是Lua的保留keyword,脚本仍然能使用它们。通过obj["name"]语法。假设一个对象有2个方法使用相同的签名可是属于不同接口,如IFoo.method()和IBar.method(),那么标记obj["IFoo.method"](obj)调用第一个版本号。
             LuaInterface在运行方法错误发生时会抛出异常,以带错误信息的异常对象。假设脚本想捕获错误,必须用pcall来调用全部方法。

    4.3处理事件


            LuaInterface中的事件有个一个Add和一个Remove方法,分别用来注冊和取消注冊事件处理。Add以Lua方法为參数。转换它到CLR相应delegate托管方法并返回。Remove以事件处理delegate托管为參数。移除处理器,例如以下:
    代码:

    function handle_mouseup(sender,args)
    print(sender:ToString() .. ’ MouseUp!’)
    button.MouseUp:Remove(handler)
    end
    handler = button.MouseUp:Add(handle_mouseup)


            脚本相同能够使用事件对象的add和remove方法来注冊事件处理(usually add EventName and remove EventName),,可是add不返回delegate托管对象,因此函数以这样的方式注冊后不能取消注冊。

    4.4托管Delegates和子类化subtyping


    LuaInterface提供3中动态创建类型的方法来扩展CLR。
    第一种已经谈到在事件处理程序的上下文中: 通过 Lua 函数托付估计在哪里。LuaInterface 创建一个新的托付类型并将其传递给 CLR。


    另外一种方法是传递一个Lua table。当中实现了接口。LuaInterface创建一个新的接口实现的类型。这个类型的对象方法托管到table。例如以下:
    代码:

    -- interface ISample { int DoTask(int x, int y); }
    -- SomeType.SomeMethod signature: int SomeMethod(ISample i)
    -- obj is instance of SomeType
    sum = {}
    function sum:DoTask(x,y)
    return x+y
    end
    -- sum is converted to instance of ISample
    res = obj:SomeMethod(sum)


            假设接口中有重载函数,全部版本号函数都会托管到一个Lua函数,这个函数依据參数类型确定哪个版本号的被调用。LuaInterface不能传递out參数给函数,可是函数必须一起返回这些值和ref參数的输出值,例如以下
    代码:

    -- interface ISample2 { void DoTask1(ref int x, out int y);
    -- int DoTask2(int x, out int y); }
    -- SomeType.SomeMethod signature: int SomeMethod(ISample i)
    -- obj is instance of SomeType
    inc = {}
    function inc:DoTask1(x)
    return x+1,x
    end
    function inc:DoTask2(x)
    return x+1,x
    end
    res = obj:SomeMethod(sum)


              最后一种创建新CLR类型的方式是子类化已经存在的类,用Lua table的函数来重写一些或全部它的virtual方法(假设 Lua table不会重写的方法 LuaInterface 使用的原始版本号)。

    table函数调用父类的函数通过一个名字为base的字段。

              为了将一个table变成一个子类的实例。脚本必须调用make_object函数。table 并将作为參数创建子类的类类型引用。

    以下的演示样例演示如何创建子类:例如以下:
    代码:

    -- class SomeObject {
    -- public virtual int SomeMethod(int x, int y) { return x+y; } }
    -- SomeType.SomeMethod signature: int SomeMethod(SomeObject o)
    -- obj is instance of SomeType
    some_obj = { const = 4 }
    function some_obj:SomeMethod(x,y)
    local z = self.base:SomeMethod(x,y)
    return z * self.const
    end
    SomeObject = luanet.import_type(’SomeObject’)
    luanet.make_object(some_obj,SomeObject)
    res = some_obj:SomeMethod(2,3) -- returns 20
    res = some_obj:ToString() -- calls base method
    res = obj:SomeMethod(some_obj) -- passing as argument


           在实现接口应用在子类化过程中,关于重载和out/ref參数存在相同的问题。最后,free_object函数曾经面make_object调用的table參数,服务table和CLR子类实例的连接。脚本必须在丢弃table的引用前使用这种方法,不然会造成内存泄露。


    【完】

    应用:

    【USAGE】
    导入资源包然后向'uLua/Plugins/'路径下的Plugins 目录复制到 Assets下将 LuaInterface 命名空间加入到您的脚本查看examples 中的一些基本使用方法。main代码是非常具有可读性 (Lua.cs) 和 LuaInterface 手冊。

    【Lua 'require' or 'dofile'】
    为了导入文件要求 and/or dofile 文件,您必须拥有text asset放在您的项目根目录'Assets/Resources' 内。它必须将命名为 *.lua.txt'。
    比如:
    'Assets/Resources/MyDir/myscript.lua.txt'

    然后在你的lua代码中能够要求:
    'require("MyDir/myscript.lua")'

    1】下载到ulua的资源包。导入project中。依照说明,将当中的Plugins目录中的内容总体复制到project的Plugins目录中;

    (这一步可能会出现找不到dll的错误,我这里是重新启动Unity解决的)

    导入后project的根目录有以下这些东西:

    lua,unity3d,解析,脚本,方法0

    2】在.txt文件里编写一些Lua脚本。比方:

    lua,unity3d,解析,脚本,方法1

    (注意:此处.txt脚本的后缀名是".txt")

    3】将这个存有Lua脚本的.txt文件载入到游戏中,资源类型是"TextAsset":

    方法任选,比方:

    ①放到Resources目录中。Resources.Load()来载入;

    ②放到project中随意地方。使用Resoueces.LoadAtPath()来载入。

    ③打成AssetBundle,放到文件server上。使用WWW来异步载入。

    假设使用③的话,推荐一个名字叫做"HFS"的虚拟文件server的小工具非常方便。仅仅需点一下,就可以模拟一个文件server出来:

    lua,unity3d,解析,脚本,方法2。非常好用)

    4】解析Lua脚本:

    1 LuaState ls = new LuaState();
    2 ls.DoString(luaString);              //luaString是载入进来的文档中的字符。类型是string
    3 LuaFunction lf = ls.GetFunction("luaFunc");  //luaFunc是Lua脚本中编写的方法名
    4 object[] r = lf.Call("2");            //括号里的"2"是要传递到Lua中的方法中的參与整型运算的值
    5 return r[0].ToString();              //r[0]即是运算后返回的值,类型是object。用之前,须要转一下类型

    非常easy。综上,Lua与Unity3d中的C#的联系。互相传递方法和參数。就OK了。

    你会看到,真的有外部的逻辑在正在运行的游戏中起作用了。

  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5244657.html
Copyright © 2020-2023  润新知