本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi)
width="150" height="210" frameborder="0" scrolling="no" src="http://widget.weibo.com/relationship/bulkfollow.php?language=zh_cn&uids=1916000601&wide=1&color=FFFFFF,FFFFFF,0082CB,666666&showtitle=0&showinfo=1&sense=0&verified=1&count=1&refer=http%3A%2F%2Fwww.himigame.com%2Flua1%2F1343.html&dpc=1" style="border-width: 0px; margin: 0px; padding: 0px; font-family: arial, helvetica, clean, sans-serif; font-size: 12px; line-height: 16px; text-align: left; ">
在使用Cocos2d-x 时候,难免需要C/C++调用Lua函数、数据或Lua调用C/C++函数,那么本篇讲详细介绍C/C++与Lua之间的数据、函数交互。
首先让我们来简单了解几个Lua API函数:
int luaL_dofile
加载并运行指定文件,没有错误返回0
void lua_settop
参数允许传入任何可接受的索引以及 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。 如果 index 为 0 ,把栈上所有元素移除。
void lua_getglobal
把全局变量 name 里的值压入堆栈。
void lua_pop
从堆栈中弹出 n
void lua_pushstring
把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝), 因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。 字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。
更多的API请参考:http://www.codingnow.com/2000/download/lua_manual.html
了解了以上几个函数,为了方便童鞋们使用,Himi直接贴出封装好的类 HclcData,其中主要包括如下几个功能:
1. C/C++ 调用 Lua 全局变量
2. C/C++ 调用 Lua 全局Table 某元素
3. C/C++ 调用 Lua 全局Table
4. C/C++ 调用 Lua 函数
5. Lua 调用C/C++ 函数
下面直接贴出代码:HclcData.h
//
// HclcData.h
// CppLua
//
// Created by Himi on 13-4-17.
//
//
#ifndef __CppLua__HclcData__
#define __CppLua__HclcData__
#include "cocos2d.h"
using namespace cocos2d;
using namespace std;
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
class HclcData{
public:
static HclcData* sharedHD();
//------------ c++ -> lua ------------//
/*
getLuaVarString : 调用lua全局string
luaFileName = lua文件名
varName = 所要取Lua中的变量名
*/
const char* getLuaVarString(const char* luaFileName,const char* varName);
/*
getLuaVarOneOfTable : 调用lua全局table中的一个元素
luaFileName = lua文件名
varName = 所要取Lua中的table变量名
keyName = 所要取Lua中的table中某一个元素的Key
*/
const char* getLuaVarOneOfTable(const char* luaFileName,const char* varName,const char* keyName);
/*
getLuaVarTable : 调用lua全局table
luaFileName = lua文件名
varName = 所要取的table变量名
(注:返回的是所有的数据,童鞋们可以自己使用Map等处理)
*/
const char* getLuaVarTable(const char* luaFileName,const char* varName);
/*
callLuaFunction : 调用lua函数
luaFileName = lua文件名
functionName = 所要调用Lua中的的函数名
*/
const char* callLuaFunction(const char* luaFileName,const char* functionName);
//------------ lua -> c++ ------------//
void callCppFunction(const char* luaFileName);
private:
static int cppFunction(lua_State* ls);
static bool _isFirst;
static HclcData* _shared;
const char* getFileFullPath(const char* fileName);
~HclcData();
};
#endif /* defined(__CppLua__HclcData__) */
HclcData.cpp
//
// HclcData.cpp
// CppLua
//
// Created by Himi on 13-4-17.
//
//
#include "HclcData.h"
#include "CCLuaEngine.h"
bool HclcData::_isFirst;
HclcData* HclcData::_shared;
HclcData* HclcData::sharedHD(){
if(!_isFirst){
_shared = new HclcData();
}
return _shared;
}
const char* HclcData::getLuaVarString(const char* luaFileName,const char* varName){
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if(isOpen!=0){
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_settop(ls, 0);
lua_getglobal(ls, varName);
int statesCode = lua_isstring(ls, 1);
if(statesCode!=1){
CCLOG("Open Lua Error: %i", statesCode);
return NULL;
}
const char* str = lua_tostring(ls, 1);
lua_pop(ls, 1);
return str;
}
const char* HclcData::getLuaVarOneOfTable(const char* luaFileName,const char* varName,const char* keyName){
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if(isOpen!=0){
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, varName);
int statesCode = lua_istable(ls, -1);
if(statesCode!=1){
CCLOG("Open Lua Error: %i", statesCode);
return NULL;
}
lua_pushstring(ls, keyName);
lua_gettable(ls, -2);
const char* valueString = lua_tostring(ls, -1);
lua_pop(ls, -1);
return valueString;
}
const char* HclcData::getLuaVarTable(const char* luaFileName,const char* varName){
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if(isOpen!=0){
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, varName);
int it = lua_gettop(ls);
lua_pushnil(ls);
string result="";
while(lua_next(ls, it))
{
string key = lua_tostring(ls, -2);
string value = lua_tostring(ls, -1);
result=result+key+":"+value+"\t";
lua_pop(ls, 1);
}
lua_pop(ls, 1);
return result.c_str();
}
const char* HclcData::callLuaFunction(const char* luaFileName,const char* functionName){
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if(isOpen!=0){
CCLOG("Open Lua Error: %i", isOpen);
return NULL;
}
lua_getglobal(ls, functionName);
lua_pushstring(ls, "Himi");
lua_pushnumber(ls, 23);
lua_pushboolean(ls, true);
/*
lua_call
第一个参数:函数的参数个数
第二个参数:函数返回值个数
*/
lua_call(ls, 3, 1);
const char* iResult = lua_tostring(ls, -1);
return iResult;
}
void HclcData::callCppFunction(const char* luaFileName){
lua_State* ls = CCLuaEngine::defaultEngine()->getLuaStack()->getLuaState();
/*
Lua调用的C++的函数必须是静态的
*/
lua_register(ls, "cppFunction", cppFunction);
int isOpen = luaL_dofile(ls, getFileFullPath(luaFileName));
if(isOpen!=0){
CCLOG("Open Lua Error: %i", isOpen);
return;
}
}
int HclcData::cppFunction(lua_State* ls){
int luaNum = (int)lua_tonumber(ls, 1);
int luaStr = (int)lua_tostring(ls, 2);
CCLOG("Lua调用cpp函数时传来的两个参数: %i %s",luaNum,luaStr);
/*
返给Lua的值
*/
lua_pushnumber(ls, 321);
lua_pushstring(ls, "Himi");
/*
返给Lua值个数
*/
return 2;
}
const char* HclcData::getFileFullPath(const char* fileName){
return CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName).c_str();
}
HclcData::~HclcData(){
CC_SAFE_DELETE(_shared);
_shared=NULL;
}
大家可以直接拿来用的,使用简单,测试如下:
首先C++测试代码:
#include "HclcData.h"
CCLOG("Str = %s",HclcData::sharedHD()->getLuaVarString("Test.lua","luaStr"));
CCLOG("Str2 %s",HclcData::sharedHD()->getLuaVarString("Test.lua","luaStr2"));
CCLOG("age = %s",HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable","age"));
CCLOG("name = %s",HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable","name"));
CCLOG("sex = %s",HclcData::sharedHD()->getLuaVarOneOfTable("Test.lua", "luaTable","sex"));
CCLOG("Table = %s",HclcData::sharedHD()->getLuaVarTable("Test.lua", "luaTable"));
CCLOG("Call Lua Function Back: %s",HclcData::sharedHD()->callLuaFunction("Test.lua", "luaLogString"));
HclcData::sharedHD()->callCppFunction("Test.lua");
HclcData::sharedHD()->callLuaFunction("Test.lua", "call_Cpp");
对应测试的Test.Lua文件:
luaStr = "I' m Himi"
luaStr2 = "are you ok!"
luaTable={age = 23,name="Himi",sex="男"}
function luaLogString(_logStr,_logNum,_logBool)
print("Lua 脚本打印从C传来的字符串:",_logStr,_logNum,_logBool)
return "call lua function OK"
end
function call_Cpp(_logStr,_logNum,_logBool)
num,str = cppFunction(999,"I'm a lua string")
print("从cpp函数中获得两个返回值:",num,str)
end
运行测试结果如下:
Cocos2d: Str = I' m Himi
Cocos2d: Str2 are you ok!
Cocos2d: age = 23
Cocos2d: name = Himi
Cocos2d: sex = 男
Cocos2d: Table = name:Himi age:23 sex:男
Lua 脚本打印从C传来的字符串: Himi 23 true
Cocos2d: Call Lua Function Back: call lua function OK
Cocos2d: Lua调用cpp函数时传来的两个参数: 999 I'm a lua string
从cpp函数中获得两个返回值: 321 Himi
在Himi做这些交互时出现了如下错误:
“PANIC: unprotected error in call to Lua API (attempt to index a nil value)
如下图:
最后Himi发现造成此问题的原因有两种:
1. 是你的lua文件位置路径!
细心的童鞋应该看到,每次我使用 luaL_dofile 函数时传入的都是调用了一个getFileFullPath的函数进行获取文件的完整路径!
在HclcData中包装了一个函数:
const char*HclcData::getFileFullPath(const char*fileName){
returnCCFileUtils::sharedFileUtils()->fullPathForFilename(fileName).c_str();
}
2. 如果你是cpp调用lua函数,那么你的这个lua函数不能是local的!
反之,如果你lua调用cpp函数,同理,cpp函数肯定是static的!
另外,如果你cpp调用lua,等同于重新加载了这个lua文件,是不同的对象!因此你应该建立一个新的lua文件,主要用于交互所用!
例如你a.lua中有一个tab的成员变量,那么你使用cpp调用lua函数后,这个tab是新的对象!
最后附上HclcData和Test.lua 下载地址:http://vdisk.weibo.com/s/y0zws
OK,本篇就到这里,有什么问题及时联系Himi!