一、前言
项目工程地址:https://gitee.com/hankangwen/LuaFramework_UGUI_V2
项目将持续更新。
二、Lua与C的交互
Lua可以作为程序库用来扩展应用的功能,也就是Lua可以作为扩展性语言的原因所在。同时,Lua程序中可以注册有其他语言实现的函数,这些函数可能由C语言或者其他语言实现,可以增加一些不容易由Lua实现的功能。
在C和Lua之间通信关键内容在于一个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C和Lua之间的数据交互也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。
栈的使用解决了C和Lua之间两个不协调的问题:第一,Lua会自动进行垃圾收集,而C要求显示的分配存储单元,两者引起的矛盾。第二,Lua中的动态类型和C中的静态类型不一致引起的混乱。
三、在Lua中调用C的方法
扩展Lua基础方法之一就是为应用程序注册新的C函数到Lua中。
从Lua调用C函数,我们必须注册函数,也就是说,我们必须把C函数的地址以一个适当的方式传递给Lua解释器。
当Lua调用C函数的时候,使用和C调用Lua相同类型的栈来交互。C函数从栈中获取她的参数,调用结束后将返回结果放到栈中。为了区分返回结果和栈中的其他值,每个C函数还会返回结果的个数。这儿有一个重要的概念:用来交互的栈不是全局变量,每个函数有自己的私有栈。甚至当一个C函数调用Lua代码(Lua代码调用同一个C函数或者其他的C函数),每一个C函数都由自己的独立的私有栈,并且第一个参数在index=1的位置。
下面来展示一个C#脚本打成wrap包给Lua调用的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestPrint3
{
public static void Log()
{
Debug.Log("TestPrint3 Log:");
}
}
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
static int Log(IntPtr L)
{
try
{
ToLua.CheckArgsCount(L, 0);
TestPrint3.Log();
return 0;
}
catch (Exception e)
{
return LuaDLL.toluaL_exception(L, e);
}
}
Wrap中会检查参数个数是否正确。如果参数>0,则还会检查参数类型,然后才调用C#的方法。
四、备忘知识
1.require函数
Lua提供高级的require函数来加载运行库。粗略的说require和dofile完成同样的功能但有两点不同:
1.require会搜索目录加载文件;
2.require会判断文件是否已经加载避免重复加载同一个文件。由于上述特征,require在Lua中是加载库的更好函数。
3.如果需要在LuaFramework/Lua下新增加一个文件夹,则需要把打出来的代码包加到LuaManager.cs中。