今天继续学习Lua和C#的交互,今天要讲的是加载Lua文件。
之后的例子都会使用tolua来写,因为tolua提供的lua原生api比xlua更多。当然你也可以自己编译lua的dll放到unity里面。


加载文件使用的是luaL_loadfile这个api,案例如下:
结果是先打印100,再打印200

var L = LuaDLL.luaL_newstate();
var path = Application.dataPath + "/Examples/02_LoadFile/02.lua";
var errorPath = Application.dataPath + "/02.lua";

//返回结果不是0代表加载失败
var result = LuaDLL.luaL_loadfile(L, path);
//Debug.Log(result);
if ( result!= 0) 
{
    Debug.LogError(LuaDLL.lua_tostring(L, -1));
}

if(LuaDLL.lua_pcall(L, 0, 0, 0) != 0)
{
    Debug.LogError(LuaDLL.lua_tostring(L, -1));
}

LuaDLL.lua_getglobal(L,"a");
LuaDLL.lua_getglobal(L,"b");

if (LuaDLL.lua_isnumber(L, -2) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-2));
}

if (LuaDLL.lua_isnumber(L, -1) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-1));
}

LuaDLL.lua_close(L);

Lua代码如下:

a = 100
b = 200

Lua里面暂时不写函数,关于函数的调用会在之后讲。


接下来解释代码:

var result = LuaDLL.luaL_loadfile(L, path);
//Debug.Log(result);
if ( result!= 0) 
{
    Debug.LogError(LuaDLL.lua_tostring(L, -1));
}
luaL_loadfile(IntPtr luaState, string filepath)

第一个参数传入luaState,关于luaState,第一篇文章讲了。第二个参数传入文件路径。返回值是数字,如果返回0代表成功,0以外的代表失败
如果路径是正确的,没有什么好说的。如果是失败,lua是不会自己报错的。

出错时,lua会把错误信息压入栈中,所以需要调用LuaDLL.lua_tostring(L, -1) 把错误信息拿出来。

当传入错误路径时,错误信息如下:

lua 引用其他文件夹的模块 lua 加载所有lua文件_Lua


if(LuaDLL.lua_pcall(L, 0, 0, 0) != 0)
 {
     Debug.LogError(LuaDLL.lua_tostring(L, -1));
 }
lua_pcall(IntPtr luaState, int nArgs, int nResults, int errfunc)

这个函数的作用是运行之前加载的lua文件,使用loadfile后lua虚拟机并不会运行代码,只会编译代码,所以需要调用pcall。
lua_pcall包含了四个参数,分别是luaState,参数个数,返回值个数,错误处理函数在栈中的索引。本篇案例是最简单的情况,因为Lua代码没有方法,也就没有参数个数,没有返回值,我们也不处理错误。所以后面三个参数都是0。关于这个方法的复杂情况,以后会讲。

另外,luaL_loadfilelua_pcall两步可以直接用luaL_dofile替代。


LuaDLL.lua_getglobal(L,"a");
 LuaDLL.lua_getglobal(L,"b");
关于lua的栈

lua的栈是用来处理lua和其它语言交互的部分,并不是lua内部跑的代码都在这个栈上。lua内部有自己的内存区用来管理lua自身的代码。所以即使执行了lua文件,lua文件里面的公共变量也不是在栈上。

lua_getglobal(IntPtr luaState, string name)

lua_getglobal把lua里的公共变量压栈,以便C#端能够调用。上面两行代码的意思是把"a"和"b"分别压栈。


if (LuaDLL.lua_isnumber(L, -2) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-2));
}

if (LuaDLL.lua_isnumber(L, -1) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-1));
}
lua_isnumber(IntPtr luaState, int idx)

最后打印结果,lua_isnumber上篇也讲了,不过上篇文章用的是xlua,xlua封装lua原生api的时候把返回值改成bool了,实际上lua原生api是返回int值。返回1代表true,返回0代表false
注意,当调用lua_tonumber时并不会把返回的值出栈。如果想把栈顶出栈,需要调用LuaDLL.lua_pop(L,1)。可以尝试下面的代码:
结果是先打印最后入栈的b的值200,再打印a的值100

if (LuaDLL.lua_isnumber(L, -1) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-1));
}

LuaDLL.lua_pop(L,1);
if (LuaDLL.lua_isnumber(L, -1) == 1)
{
    Debug.Log(LuaDLL.lua_tonumber(L,-1));
}

那么这次的内容就这些了,
github工程地址对应的是Examples/02_LoadFile文件夹。