tolua

例子1

展示了最小的tolua#环境,以及执行一段lua代码操作代码如下:

        LuaState lua = new LuaState();
        lua.Start();
        string hello =
            @"                
                print('hello tolua#')                                  
            ";
        
        lua.DoString(hello, "HelloWorld.cs");
        lua.CheckTop();
        lua.Dispose();
        lua = null;

LuaState封装了对lua 主要数据结构 lua_State 指针的各种堆栈操作。
一般对于客户端,推荐只创建一个LuaState对象。如果要使用多State需要在Unity中设置全局宏 MULTI_STATE

例子2

展示了dofile跟require的区别, 代码如下:

    LuaState lua = null;

    void Start () 
    {      
        lua = new LuaState();                
        lua.Start();        
        //如果移动了ToLua目录,需要自己手动,这里只是例子就不做配置了
        string fullPath = Application.dataPath + "/ToLua/Examples/02_ScriptsFromFile";
        lua.AddSearchPath(fullPath);        
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(50, 50, 120, 45), "DoFile"))
        {
            lua.DoFile("ScriptsFromFile.lua");                        
        }
        else if (GUI.Button(new Rect(50, 150, 120, 45), "Require"))
        {            
            lua.Require("ScriptsFromFile");            
        }

        lua.Collect();
        lua.CheckTop();
    }

    void OnApplicationQuit()
    {
        lua.Dispose();
        lua = null;
    }

tolua#DoFile函数,跟lua保持一致行为,能多次执行一个文件。tolua#加入了新的Require函数,无论c#和lua谁先require一个lua文件, 都能保证加载唯一性

注意: 虽然有文件加载,但此例子无法发布到手机, 如果ToLua目录不在/Assets目录下, 需要修改代码中的目录位置

例子3 LuaFunction

展示了如何调用lua的函数, 主要代码如下:

    private string script =
        @"  function luaFunc(num)                        
                return num + 1
            end

            test = {}
            test.luaFunc = luaFunc
        ";

    LuaFunction luaFunc = null;
    LuaState lua = null;
	
    void Start () 
    {
        new LuaResLoader();
        lua = new LuaState();
        lua.Start();
        DelegateFactory.Init();
        lua.DoString(script);

        //Get the function object
        luaFunc = lua.GetFunction("test.luaFunc");

        if (func != null)
        {
            int num = luaFunc.Invoke<int, int>(123456);
            Debugger.Log("generic call return: {0}", num);

            num = CallFunc();
            Debugger.Log("expansion call return: {0}", num);

            Func<int, int> Func = luaFunc.ToDelegate<Func<int, int>>();
            num = Func(123456);
            Debugger.Log("Delegate call return: {0}", num);
            
            num = lua.Invoke<int, int>("test.luaFunc", 123456, true);
            Debugger.Log("luastate call return: {0}", num);
        }
                
        lua.CheckTop();
	}

    void OnDestroy()
    {
        if (luaFunc != null)
        {
            luaFunc.Dispose();
            luaFunc = null;
        }

        lua.Dispose();
        lua = null;
    }

    int CallFunc()
    {        
        luaFunc.BeginPCall();                
        luaFunc.Push(123456);
        luaFunc.PCall();        
        int num = (int)luaFunc.CheckNumber();                    
        luaFunc.EndPCall();
        return num;                
    }

tolua# 简化了lua函数的操作,通过LuaFunction封装(并缓存)一个lua函数,并提供各种操作, 建议频繁调用函数使用无GC方式。

注意: 无论Call还是PCall只相当于lua中的函数’.’调用。
请注意’:’这种语法糖 self:call(…) == self.call(self, …)
c# 中需要按后面方式调用, 即必须主动传入第一个参数self

例子4

展示了如何访问lua中变量,table的操作

    private string script =
        @"
            print('Objs2Spawn is: '..Objs2Spawn)
            var2read = 42
            varTable = {1,2,3,4,5}
            varTable.default = 1
            varTable.map = {}
            varTable.map.name = 'map'
            
            meta = {name = 'meta'}
            setmetatable(varTable, meta)
            
            function TestFunc(strs)
                print('get func by variable')
            end
        ";

    void Start () 
    {
        new LuaResLoader();
        LuaState lua = new LuaState();
        lua.Start();
        lua["Objs2Spawn"] = 5;
        lua.DoString(script);

        //通过LuaState访问
        Debugger.Log("Read var from lua: {0}", lua["var2read"]);
        Debugger.Log("Read table var from lua: {0}", lua["varTable.default"]);  //LuaState 拆串式table

        LuaFunction func = lua["TestFunc"] as LuaFunction;
        func.Call();
        func.Dispose();

        //cache成LuaTable进行访问
        LuaTable table = lua.GetTable("varTable");
        Debugger.Log("Read varTable from lua, default: {0} name: {1}", table["default"], table["map.name"]);
        table["map.name"] = "new";  //table 字符串只能是key
        Debugger.Log("Modify varTable name: {0}", table["map.name"]);

        table.AddTable("newmap");
        LuaTable table1 = (LuaTable)table["newmap"];
        table1["name"] = "table1";
        Debugger.Log("varTable.newmap name: {0}", table1["name"]);
        table1.Dispose();

        table1 = table.GetMetaTable();

        if (table1 != null)
        {
            Debugger.Log("varTable metatable name: {0}", table1["name"]);
        }

        object[] list = table.ToArray();

        for (int i = 0; i < list.Length; i++)
        {
            Debugger.Log("varTable[{0}], is {1}", i, list[i]);
        }

        table.Dispose();                        
        lua.CheckTop();
        lua.Dispose();
    }

例子5 协同一

展示了如何使用lua协同, lua 代码如下:

        function fib(n)
            local a, b = 0, 1
            while n > 0 do
                a, b = b, a + b
                n = n - 1
            end

            return a
        end

        function CoFunc()
            print('Coroutine started')    
            for i = 1, 10, 1 do
                print(fib(i))                    
                coroutine.wait(0.1)                     
            end 
            print("current frameCount: "..Time.frameCount)
            coroutine.step()
            print("yield frameCount: "..Time.frameCount)

            local www = UnityEngine.WWW("http://www.baidu.com")
            coroutine.www(www)
            local s = tolua.tolstring(www.bytes)
            print(s:sub(1, 128))
            print('Coroutine ended')
        end

        function TestCortinue() 
            coroutine.start(CoFunc)
        end

        local coDelay = nil

        function Delay()
            local c = 1

            while true do
                coroutine.wait(1) 
                print("Count: "..c)
                c = c + 1
            end
        end

        function StartDelay()
            coDelay = coroutine.start(Delay)
        end

        function StopDelay()
            coroutine.stop(coDelay)
        end

c#代码如下:

        new LuaResLoader();
        lua  = new LuaState();
        lua.Start();
        LuaBinder.Bind(lua);
        DelegateFactory.Init();         
        looper = gameObject.AddComponent<LuaLooper>();
        looper.luaState = lua;

        lua.DoString(luaFile.text, "TestLuaCoroutine.lua");
        LuaFunction f = lua.GetFunction("TestCortinue");
        f.Call();
        f.Dispose();
        f = null;