Cocos2d x手動繫結C 類到Lua

2021-06-22 22:12:06 字數 4840 閱讀 8058

最近開始學習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"   |-1

2| userdata |-2

1| string parameter |-3

lua_setmetatable將位於lua棧中-2位置的userdata新增到元表lual_foo中。最後,返回值1使得lua可以得到userdata,之後棧將會被清空。

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_registersfooregs新增到lual_foo中。lua_pushvalue將lual_foo元表中元素的拷貝壓入棧中。lua_setfield將lual_foo元表的index域設為__indexlua_setglobal將元表lual_foo重新命名為foo並將它設為lua的全域性變數,這樣lua可以通過識別foo來訪問元表lual_foo,並使lua指令碼能夠覆蓋元表foo,即覆蓋c++函式。如此一來,使用者可以用lua**自定功能,覆蓋掉c++類中函式的功能,極大地提高了**靈活性。

現在新增繫結函式的函式宣告至fun.h中:

int l_foo_constructor(lua_state * l);

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

新增如下**到fun.lua

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開始逐漸修復...