今天继续学习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) 把错误信息拿出来。
当传入错误路径时,错误信息如下:
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_loadfile和lua_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文件夹。