ToLua

例子1

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

using UnityEngine;
using LuaInterface;
using System;

public class HelloWorld : MonoBehaviour
{
    void Awake()
    {
        LuaState lua = new LuaState(); //1、创建一个lua的虚拟机
        lua.Start();                   //2、启动lua虚拟机
        string hello =                 //3、声明一个字符串
            @"                
                print('hello tolua#')                                  
            ";
        
        lua.DoString(hello, "HelloWorld.cs");//4、调用lua虚拟机在DoString方法
                                             //使用完后准备开始销毁lua虚拟机
        lua.CheckTop(); //                   //5、检查堆栈是否平衡,一般放在update中,C#调用lua都需要调用者自己控制堆栈平衡
        lua.Dispose();                       //6、析构掉lua虚拟机以及其资源
        lua = null;                          //7、置空完毕
    }
}

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

  • LuaState.Start 需要在tolua代码加载到内存后调用。如果使用assetbunblde加载lua文件,调用Start()之前assetbundle必须加载好
  • LuaState.DoString 执行一段lua代码,除了例子,比较少用这种方式加载代码,无法避免代码重复加载覆盖等,需调用者自己保证。第二个参数用于调试信息,或者error消息(用于提示出错代码所在文件名称)
  • LuaState.CheckTop 检查是否堆栈是否平衡,一般放于update中,c#中任何使用lua堆栈操作,都需要调用者自己平衡堆栈(参考LuaFunction以及LuaTable代码), 当CheckTop出现警告时其实早已经离开了堆栈操作范围,这是需自行review代码。
  • LuaState.Dispose 释放LuaState 以及其资源。
  • 1:使用Tolua的相关类及方法都需要调用命名空间LuaInterface

    2:调用lua脚本必须要先创建一个lua的虚拟机,而创建的步骤就是LuaState lua = new LuaState();, 创建一个LuaState型的对象,这个就是lua的虚拟机,后面的lua的与C#的交互全部依仗这个东西
    3:lua中直接运行一段lua脚本最简单的方法就是 lua.DoString, 该方法声明如下:

    public object[] DoString(string chunk, string chunkName = "LuaState.DoString")
    4:使用完lua虚拟机之后记得要销毁,具体操作如下:先进行lua虚拟机栈的判空,具体对应的就是lua.CheckTop , 然后就是析构掉lua虚拟机,具体方法为lua.Dispose

注意: 此例子无法发布到手机

例子2

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

using UnityEngine;
using System.Collections;
using LuaInterface;
using System;
using System.IO;

//展示searchpath(查找指定文件) 使用,require 与 dofile 区别
public class ScriptsFromFile : MonoBehaviour 
{
    LuaState lua = null;                     //1、声明一个LuaState
    private string strLog = "";              //2、声明一个私有的字符串

	void Start () 
    {
#if UNITY_5 || UNITY_2017 || UNITY_2018		
        Application.logMessageReceived += Log;//3、绑定一个log方法
#else
        Application.RegisterLogCallback(Log);
#endif         
        lua = new LuaState();                //4、实例化一个lua虚拟机
        lua.Start();                         //5、启动lua虚拟机
        //如果移动了ToLua目录,自己手动修复吧,只是例子就不做配置了
        string fullPath = Application.dataPath + "\\LuaFramework/ToLua/Examples/02_ScriptsFromFile"; //6、拼接ScriptsFromFile.lua在工程中的路径
        lua.AddSearchPath(fullPath);        //7、通过AddSearchPath添加到lua可搜索的路径中
    }

    void Log(string msg, string stackTrace, LogType type)
    {
        strLog += msg;
        strLog += "\r\n";
    }

    void OnGUI()
    {
        GUI.Label(new Rect(100, Screen.height / 2 - 100, 600, 400), strLog);

        if (GUI.Button(new Rect(50, 50, 120, 45), "DoFile"))
        {
            strLog = "";
            lua.DoFile("ScriptsFromFile.lua");    //8、通过DoFile加载文件到虚拟机中                    
        }
        else if (GUI.Button(new Rect(50, 150, 120, 45), "Require"))
        {
            strLog = "";            
            lua.Require("ScriptsFromFile");       //9、通过Require加载文件到虚拟机中        
        }

        lua.Collect();                            //10、垃圾回收,被自动gc的LuaFunction, LuaTable,以及委托减掉的LuaFunction, 
                                                  //延迟删除的Object之类。等等需要延迟处理的回收, 都在这里自动执行
        lua.CheckTop();                           //11、检查堆栈是否平衡,一般放在update中,C#调用lua都需要调用者自己控制堆栈平衡
    }

    void OnApplicationQuit()
    {
        lua.Dispose();                            //12、析构掉lua虚拟机以及其资源
        lua = null;                               //13、置空完毕
#if UNITY_5 || UNITY_2017 || UNITY_2018	
        Application.logMessageReceived -= Log;    //14、解除绑定
#else
        Application.RegisterLogCallback(null);
#endif 
    }
}

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

  • LuaState.AddSearchPath 增加搜索目录, 这样DoFile跟Require函数可以只用文件名,无需写全路径
  • LuaState.DoFile 加载一个lua文件, 注意dofile需要扩展名, 可反复执行, 后面的变量会覆盖之前的DoFile加载的变量
  • LuaState.Require 同lua require(modname)操作, 加载指定模块并且把结果写入到package.loaded中,如果modname存在, 则直接返回package.loaded[modname]
  • LuaState.Collect 垃圾回收, 对于被自动gc的LuaFunction, LuaTable, 以及委托减掉的LuaFunction, 延迟删除的Object之类。等等需要延迟处理的回收, 都在这里自动执行

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

例子3 LuaFunction

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

using UnityEngine;
using System.Collections;
using LuaInterface;
using System;

public class CallLuaFunction : MonoBehaviour 
{
    private string script =                 //1、test.luaFunc lua脚本
        @"  function luaFunc(num)                        
                return num + 2
            end

            test = {}
            test.luaFunc = luaFunc
        ";

    LuaFunction luaFunc = null;             //2、声明LuaFunction luaFunc并赋值初始null
    LuaState lua = null;                    //3、声明一个 LuaState
    string tips = null;                     //4、声明tip字符串
	
	void Start () 
    {
#if UNITY_5 || UNITY_2017 || UNITY_2018
        Application.logMessageReceived += ShowTips;//5、绑定ShowTips
#else
        Application.RegisterLogCallback(ShowTips);
#endif
        new LuaResLoader();                        //6、new一个 LuaResLoader
        lua = new LuaState();                      //7、实例化一个 LuaState
        lua.Start();                               //8、启动lua虚拟机
        DelegateFactory.Init();        
        lua.DoString(script);                      //9、调用lua虚拟机在DoString方法

        //Get the function object
        luaFunc = lua.GetFunction("test.luaFunc"); //10、GetFunciton得到一个LuaFunction对象

        if (luaFunc != null)
        {
            int num = luaFunc.Invoke<int, int>(123456);//11、此方法要产生gc,原因在于Call函数
                                                       //参数类型是object[] Call(params object[] args)
            Debugger.Log("generic call return: {0}", num);

            num = CallFunc();
            Debugger.Log("expansion call return: {0}", num);//12、此方法不产生gc

            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();                                     //检查堆栈是否平衡,一般放在update中,C#调用lua都需要调用者自己控制堆栈平衡
    }

    void ShowTips(string msg, string stackTrace, LogType type)
    {
        tips += msg;
        tips += "\r\n";
    }

#if !TEST_GC
    void OnGUI()
    {
        GUI.Label(new Rect(Screen.width / 2 - 200, Screen.height / 2 - 150, 400, 300), tips);
    }
#endif

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

        lua.Dispose();
        lua = null;

#if UNITY_5 || UNITY_2017 || UNITY_2018
        Application.logMessageReceived -= ShowTips;
#else
        Application.RegisterLogCallback(null);
#endif
    }

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

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

  • LuaState.GetLuaFunction 获取并缓存一个lua函数, 此函数支持串式操作, 如"test.luaFunc"代表test表中的luaFunc函数。
  • LuaState.Invoke 临时调用一个lua function并返回一个值,这个操作并不缓存lua function,适合频率非常低的函数调用。
  • LuaFunction.Call() 不需要返回值的函数调用操作
  • LuaFunction.Invoke() 有一个返回值的函数调用操作 
  • LuaFunction.BeginPCall() 开始函数调用 
  • LuaFunction.Push() 压入函数调用需要的参数,通过众多的重载函数来解决参数转换gc问题 
  • LuaFunction.PCall() 调用lua函数 
  • LuaFunction.CheckNumber() 提取函数返回值, 并检查返回值为lua number类型 
  • LuaFunction.EndPCall() 结束lua函数调用, 清楚函数调用造成的堆栈变化 
  • LuaFunction.Dispose() 释放LuaFunction, 递减引用计数,如果引用计数为0, 则从_R表删除该函数 

注意: 无论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();
    }
  • luaState["Objs2Spawn"] LuaState通过重载this操作符,访问lua _G表中的变量Objs2Spawn 
  • LuaState.GetTable 从lua中获取一个lua table, 可以串式访问比如lua.GetTable("varTable.map.name") 等于 varTable->map->name
  • LuaTable 支持this操作符,但此this不支持串式访问。比如table["map.name"] "map.name" 只是一个key,不是table->map->name 
  • LuaTable.GetMetaTable() 可以获取当前table的metatable 
  • LuaTable.ToArray() 获取数组表中的所有对象存入到object[]表中 
  • LuaTable.AddTable(name) 在当前的table表中添加一个名字为name的表 
  • LuaTable.GetTable(key) 获取t[key]值到c#, 类似于 lua_gettable 
  • LuaTable.SetTable(key, value) 等价于t[k] = v的操作, 类似于lua_settable 
  • LuaTable.RawGet(key) 获取t[key]值到c#, 类似于 lua_rawget 
  • LuaTable.RawSet(key, value) 等价于t[k] = v的操作, 类似于lua_rawset 

例子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;  
  • 必须启动LuaLooper驱动协同,这里将一个lua的半双工协同装换为类似unity的全双工协同 
  • fib函数负责计算一个斐那波契n 
  • coroutine.start 启动一个lua协同 
  • coroutine.wait 协同中等待一段时间,单位:秒 
  • coroutine.step 协同中等待一帧. 
  • coroutine.www 等待一个WWW完成. 
  • tolua.tolstring 转换byte数组为lua字符串缓冲 
  • coroutine.stop 停止一个正在lua将要执行的协同 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值