天天看点

【COCOS2DX-LUA 脚本开发之十一】C/C++与Lua之间进行数据函数交互

在使用Cocos2d-x 时候,难免需要C/C++调用Lua函数、数据或Lua调用C/C++函数,那么本篇讲详细介绍C/C++与Lua之间的数据、函数交互。

首先让我们来简单了解几个Lua API函数:

int   luaL_dofile (lua_State *L, const char *filename)  :

加载并运行指定文件,没有错误返回0

void  lua_settop (lua_State *L, int index):

参数允许传入任何可接受的索引以及 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。 如果 index 为 0 ,把栈上所有元素移除。

void   lua_getglobal (lua_State *L, const char *name):

把全局变量 name 里的值压入堆栈。

void   lua_pop (lua_State *L, int n):

从堆栈中弹出 <code>n</code> 个元素。相当于清除!

void   lua_pushstring (lua_State *L, const char *s):

把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝), 因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。 字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。

了解了以上几个函数,为了方便童鞋们使用,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++ -&gt; 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 

     varName = 所要取的table变量名 

     (注:返回的是所有的数据,童鞋们可以自己使用Map等处理) 

    const char* getLuaVarTable(const char* luaFileName,const char* varName); 

     callLuaFunction : 调用lua函数 

     functionName = 所要调用Lua中的的函数名 

    const char* callLuaFunction(const char* luaFileName,const char* functionName); 

      //------------  lua -&gt; 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 

#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()-&gt;getLuaStack()-&gt;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); 

    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){ 

    int statesCode = lua_istable(ls, -1); 

    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){ 

    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); 

    return result.c_str(); 

const char* HclcData::callLuaFunction(const char* luaFileName,const char* functionName){ 

    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调用的C++的函数必须是静态的 

    lua_register(ls, "cppFunction", cppFunction); 

        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值个数 

    return 2; 

const char* HclcData::getFileFullPath(const char* fileName){ 

    return CCFileUtils::sharedFileUtils()-&gt;fullPathForFilename(fileName).c_str(); 

HclcData::~HclcData(){ 

    CC_SAFE_DELETE(_shared); 

    _shared=NULL; 

大家可以直接拿来用的,使用简单,测试如下:

首先C++测试代码:

    CCLOG("Str = %s",HclcData::sharedHD()-&gt;getLuaVarString("Test.lua","luaStr")); 

    CCLOG("Str2 %s",HclcData::sharedHD()-&gt;getLuaVarString("Test.lua","luaStr2")); 

    CCLOG("age = %s",HclcData::sharedHD()-&gt;getLuaVarOneOfTable("Test.lua", "luaTable","age")); 

    CCLOG("name = %s",HclcData::sharedHD()-&gt;getLuaVarOneOfTable("Test.lua", "luaTable","name")); 

    CCLOG("sex = %s",HclcData::sharedHD()-&gt;getLuaVarOneOfTable("Test.lua", "luaTable","sex")); 

    CCLOG("Table = %s",HclcData::sharedHD()-&gt;getLuaVarTable("Test.lua", "luaTable")); 

    CCLOG("Call Lua Function Back: %s",HclcData::sharedHD()-&gt;callLuaFunction("Test.lua", "luaLogString")); 

    HclcData::sharedHD()-&gt;callCppFunction("Test.lua"); 

    HclcData::sharedHD()-&gt;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) 

运行测试结果如下:

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) 

如下图:

<a href="http://www.himigame.com/wp-content/uploads/2013/04/QQ20130417-1.png"></a>

最后Himi发现造成此问题的原因有两种:

1. 是你的lua文件位置路径!

      细心的童鞋应该看到,每次我使用 luaL_dofile 函数时传入的都是调用了一个getFileFullPath的函数进行获取文件的完整路径!

在HclcData中包装了一个函数:

2. 如果你是cpp调用lua函数,那么你的这个lua函数不能是local的!

    反之,如果你lua调用cpp函数,同理,cpp函数肯定是static的!

另外,如果你cpp调用lua,等同于重新加载了这个lua文件,是不同的对象!因此你应该建立一个新的lua文件,主要用于交互所用!

     例如你a.lua中有一个tab的成员变量,那么你使用cpp调用lua函数后,这个tab是新的对象!

OK,本篇就到这里,有什么问题及时联系Himi!

本文转自 xiaominghimi 51CTO博客,原文链接:http://blog.51cto.com/xiaominghimi/1180323,如需转载请自行联系原作者

继续阅读