天天看點

【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,如需轉載請自行聯系原作者

繼續閱讀