最近開始學習cocos2d-x中使用lua,而我的目標也只是顯示,部分邏輯,任務, 劇情,新手引導使用lua,網路 資料等部分打算還是使用c++,所以先看了看笨木頭介紹的簡單lua入門,在c++中呼叫lua函式,訪問lua的全域性變數以及表結構,在lua中呼叫c++函式。看完這些大概對lua的堆疊和訪問方式有一定了解。那麼我們的目標還不僅僅是這些。對於cocos2d-x3.x通過指定繫結產生hpp檔案使得可以直接在lua中使用自定義的c++類檔案。但是網上的例子都是很簡單的helloscene,並無引數傳遞,以及類成員變數的互動。這些是我想要繼續解決的部分。下面這片文章講解了手動繫結的過程和原理。
cocos2d-x 3.0開始, lua binding使用tolua++方式自動繫結底層c++類到lua層,使使用者能夠用lua方式呼叫引擎各種介面。但是使用者還是希望手動繫結某些自定義類,所以接下來的內容將一步一步講解如何手動將自定義c++類繫結到lua。
首先,定義乙個類foo,這個類就是接下來要繫結到lua的類。
注意:所有c++類檔案必須放在classes資料夾裡,所有lua檔案必須放在resources資料夾裡。
在fun.h標頭檔案中新增如下**:
#include
#include
class foo
std::string add(int a, int b)
~foo()
private:
std::string name;
};
這個類有三個函式,建構函式、add函式和析構函式。作用是輸出不同字串,以判斷各函式是否被呼叫。
開始前,先了解下繫結c++類的一些基本原理。
首先建立乙個userdata來存放c++類物件指標,然後給userdata新增元表,用index元方法對映c++類中的物件方法。
userdata
lua中userdata為自定義型別,即使用者自定義c++類型別,非lua基本型別。繫結過程中用來存放c++類物件指標,從而將c++類對映到lua中。
元表(metatable)
帶有索引的集合的表,繫結過程中用來存放和對映c++類中的物件和物件方法。
__index
元表索引,指向用來存放userdata的元表。用來索引已建立的元表棧中的c++類名以及類方法名。
接下來完成實現部分,在fun.cpp中新增如下**:
#include "fun.h"
extern
"c"// 1.
int l_foo_constructor(lua_state * l)
// 2.
foo * l_checkfoo(lua_state * l, int n)
// 3.
int l_foo_add(lua_state * l)
// 4.
int l_foo_destructor(lua_state * l)
// 5.
void registerfoo(lua_state * l)
, ,,};
lual_newmetatable(l, "lual_foo");
lual_register(l, null, sfooregs);
lua_setfield(l, -1, "__index");
lua_setglobal(l, "foo");
}
**詳解:
1. c++繫結到lua的建構函式,`lual_checkstring`用來檢查建構函式的形參是否為`string`型別並返回這個`string`。利用`lua_newuserdata`建立乙個userdata來存放`foo`類物件指標。`lual_getmetatable`將與名為`lual_foo`相關聯的元表推入棧中。此時,lua棧中的內容如下:
3| metatable "lual_foo" |-1lua_setmetatable將位於lua棧中-2位置的userdata新增到元表lual_foo中。最後,返回值1使得lua可以得到userdata,之後棧將會被清空。2| userdata |-2
1| string parameter |-3
2.lual_checkudata用來檢測形參是否為lual_foo元表中的userdata,並返回這個userdata。
3. 此函式是將c++類中的add()函式對映到lua中,lua_pushstring將字串壓入棧中,返回值1使得字串返回給lua呼叫函式。
4. 此函式是將c++類中的析構函式對映到lua中。
5. 此函式是註冊c++類到lua和註冊所有已繫結的c++函式到lua。sfooregs給每個已繫結的c++函式乙個能被lua訪問的名字。lual_newmetatable建立乙個名為lual_foo的元表並壓入棧定,lual_register將sfooregs新增到lual_foo中。lua_pushvalue將lual_foo元表中元素的拷貝壓入棧中。lua_setfield將lual_foo元表的index域設為__index。lua_setglobal將元表lual_foo重新命名為foo並將它設為lua的全域性變數,這樣lua可以通過識別foo來訪問元表lual_foo,並使lua指令碼能夠覆蓋元表foo,即覆蓋c++函式。如此一來,使用者可以用lua**自定功能,覆蓋掉c++類中函式的功能,極大地提高了**靈活性。
現在新增繫結函式的函式宣告至fun.h中:
int l_foo_constructor(lua_state * l);新增如下**到fun.lua:foo * l_checkfoo(lua_state * l, int n);
int l_foo_add(lua_state * l);
int l_foo_destructor(lua_state * l);
void registerfoo(lua_state * l);
function
foo:speak
()print
("hello, i am a foo")
endlocal
foo = foo.new
("fred")
local
m = foo:add
(3, 4)
print
(m)foo:speak
()foo.add_ = foo.add
// 1.
function
foo:add
(a, b)
return "here
comes
themagic: " .. self:add_
(a, b)
endm = foo:add
(9, 8)
print
(m)
1. 同名函式覆蓋繫結的c++函式,提高擴充套件性。
// register lua engine
auto engine = luaengine::getinstance();
scriptenginemanager::getinstance()->setscriptengine(engine);
// adding code here...
// register lua binding
registerfoo(engine->getluastack()->getluastate());
std::string path = fileutils::getinstance()->fullpathforfilename("fun.lua");
engine->executescriptfile(path.c_str());
注意:因為cocos2d-x lua binding目前不支援多個狀態,所以在註冊已繫結的c++類時,只能使用當前執行的狀態。
執行程式,如果得到下面的輸出結果證明已經繫結成功:
foo is born
cocos2d: [lua-print] fred: 3 + 4 = 7
cocos2d: [lua-print] hello, i am a foo
cocos2d: [lua-print] here comes the magic: fred: 9 + 8 = 17
android環境測試:
如果希望在android環境下除錯,在執行proj.android/build_native指令碼前,需要在proj.android/jni/android.mk檔案中新增fun.cpp檔案包含:
local_src_files
:= hellolua/main.cpp \
../../
../../
classes/fun.cpp
Cocos2d x手動繫結C 類到Lua
cocos2d x 3.0開始,lua binding使用tolua 方式自動繫結底層c 類到lua層,使使用者能夠用lua方式呼叫引擎各種介面。但是使用者還是希望手動繫結某些自定義類,所以接下來的內容將一步一步講解如何手動將自定義c 類繫結到lua。首先,定義乙個類foo,這個類就是接下來要繫結到...
cocos2d x 布景層類
cclayer是ccnode的子類,在此基礎上實現觸屏時間 協議。可以實現ccnode 類的功能,並且可以處理輸入,包括觸屏和加速度感測器。場景中可以有很多個布景層。繼承關係如下 cclayercolor是cclayer的子類,有兩個擴充套件功能 1 為布景層增添顏色。2 設定不透明度。cclaye...
整合quickx到普通cocos2dx
quickx是對cocos2dx的lua擴充套件,它做了一些c 的擴充套件,同時還在lua做了一些封裝,讓用lua開發cocos2dx更快,中文站 由於現在的專案對cocos2dx有一些修改,又想用到quickx的便捷,於是便想把quickx 整合到現在的專案裡。先從ccluastack開始逐漸修復...