C++访问LUA中的函数

最近一个COCOS2DX项目有了较大的变化,整个项目的数据层都从C++层移到了LUA层。这下问题就来了,如何在C++层访问LUA的数据层呢?而我作为一个LUA的新人,那就纠结了,那尼马还不得啃好几本书?如果我告诉上司,我需要一周的时间,那估计要被炒掉了。但没法,任务分配了,开始干吧。

 

关于在c++代码中访问LUA函数的教程,可以说遍布网络的每个角落,大家会去教你如何使用lua_pcall,  lua_getglobal,  lua_pushnumber等。基本要求如下:

1、普通全局函数的访问(这个容易,如果只有一两个参数,一两个返回值,都能应付)

2、表内函数的访问(这个尼马,又和表扯到一起了,冒似LUA里的包也和表是同一概念,尼马难度提高了)

3、参数和返回值的类型支持INT,STRING,TABLE,参数和返回值的数量支持任意数量。(数量都不是问题,按顺序PUSH就完了,如何PUSH一个table呢????这个难度就有点高了,估计亲你得回去和度娘好好亲热一番。如果这个table嵌套了TABLE呢???是不是开始蛋疼了?肯定会有某种需求,要向LUA函数传递一个二维,甚至三维数组,你敢说这种需求不会出现?)

 

作为程序员的第一感觉,我需要做一个类来管理这所有的事情。于是我设计了一个类LuaAction用来模拟整个函数的调用过程。 

LuaAction已经上传了,下载页面:http://download.csdn.net/detail/sunshine7858/6357979

 

基本思路如下: 

LuaAction lua;                             //创建一个LuaAction对象  
lua.setModule(module);                     //设置包名,如果函数没有包名,那就跳过这行  
lua.setFunction(func);                     //设置要访问的函数名,  
lua.addStringParam(argString);             //添加第一个string参数,如果没有就跳过  
lua.addIntParam(argInt);                   //添加第二个int参数,如果没有就跳过  
lua.addTableParam(argTable);               //添加第三个table参数,如果没有就跳过  
.......                                    //添加更多的参数  
 
lua.executeFunction(resultnum);            //核心函数,要传入返回值的数量,然后找到要执行的函数,压入参数,读取返回值。  
   
string retuslt0 = lua.getStringResult(0);  //获取第1个SRING返回值  
int result1 = lua.getIntResult(1);         //获取第2个INT返回值  
table result2 = lua.getTableResult(2);     //获取第3个table返回值
....


 

而其中最难的地方,则是如何通过递归加载整个table表。而详细的实现细节比较复杂,就不在这里赘述了。基本上有了这个类,可以访问LUA中的所有公共函数,就像你在LUA层一样。由于LuaAction已经实现了多层表的嵌套,你既可以传入一个多层的TABLE,也可以返回一个多层的TABLE。这样就大大方便了LUA和C++的交互。

但LuaAction在使用前,必须调用一次他的初始化函数:

void  LuaAction::initState(LuaState* state);


剩余的事情就和上面的流程一样了。

 

有了这个类,可以说一劳永逸,我再也不用去管什么lua_gettop(),什么lua_pushstring()等。都见鬼去吧,哥再也不和你们玩了!

但时间长了后,问题又出现了,发现大家经常会访问一些简单的函数,可能只有一个参数,或没有参数,或只是想返回一个值。但在调用时,我还是要了解LuaAction的全部对外接口。而且很可能只是一个简单的string getName()函数我确要写近5行的代码,实在不划算啊,看着也累啊。好吧,为了提高代码的重用性,我将这些常用的函数都包装了起来。创建了一个LuaAactionFactory类,用来访问那些常用的函数。如:

 static void void_func_void(const char* module, const char* func);
 static void void_func_int(const char* module, const char* func, int arg1);

 static int int_func_void(const char* module, const char* func);
 static int int_func_int(const char* module, const char* func, int arg1);

 ........


 

举个例子:Lua中有一个函数如下

function getName(index)
    return tNames[index]
end


LuaAction的访问代码:

 LuaAction lua;
 lua.setModule(module);
 lua.setFunction(func);
 lua.addIntParam(arg1);
 lua.executeFunction(1);
 return lua.getStringResult(0);


LuaActionFactory访问代码:

int ret = LuaActionFactory::int_func_int(NULL, "getName", 1)

 

最后对2维数组的传递和获取做一下简单的演示:

 

有LUA函数如下:
function func(t)
	t[1] = 1
	return t
end

LuaAction的返问代码:

//创建一个要传递给函数的table参数
LuaParamTable* table = new LuaParamTable();
//以下设置各种属性
table->setInt("key1", 11);
table->setString("key2", "value1");
table->setInt(5, 22);
table->setString(6, "value2");
//创建子表
LuaParamTable* subtable = new LuaParamTable();
subtable->setInt("key3", 5556);
subtable->setString("key4", "value1");
subtable->setInt(3, 444);
subtable->setString(4, "value3");
//将子表挂到主表中
table->setTable("table", subtable);
	
LuaAction lua;                                //启动LuaAction调用函数
lua.setFunction("func");
lua.addTableParam(table);                     //压入表参数
lua.executeFunction(1);                       //执行函数

LuaParamTable tResult;					
lua.getTableResultAndClear(&tResult, 0);      //获取表对象

int a = tResult.getIntByIndex(1);             //检查在LUA中的赋值

//将返回值与之前的赋值情况进行对比
int value1 = tResult.getIntByKey("key1");
string value2 = tResult.getStringByKey("key2");
int value3 = tResult.getIntByIndex(5);
string value4 = tResult.getStringByIndex(6);

LuaParamTable tSubResult;
tResult.swapTableByKey("table", &tSubResult);
int value5 = tSubResult.getIntByKey("key3");
string value6 = tSubResult.getStringByKey("key4");
int value7 = tSubResult.getIntByIndex(3);
string value8 = tSubResult.getStringByIndex(4);
切记:作为表参数时,LuaParamTable是new出来的,因为他的生命周期要交给LuaAction去管理。作为返回值时,LuaParamTable是直接在栈上创建的,因为他自己要管理自己的生命周期。


相信有了以上的工具,基本上大部分的LUA函数都能访问了。

你可能感兴趣的:(C++,function,lua)