天天看點

學習Cocos2d-x Lua:綁定自定義類到Runtime(Lua-binding)

這個系列我們主要學習Cocos2d-x Lua,總結Lua開發過程中所涉及的知識點,以及在開發過程中如何使用Cocos Code IDE。這一篇講解綁定自定義類到Runtime。

       現在我們的需求是:在C++層定義了一些類,我們需要将這些類導出給Lua來使用,進而完成在C++層實作起來容易的需要,這個時候就需要将整個類作為子產品導出。而Cocos2d-x正是采用的這種思想,将Cocos中的類導出供使用者使用,而不是再寫一套Lua代碼,使用者使用Cocos導出的這套接口,在Lua腳本層寫遊戲代碼。

為了更好的了解這部分的内容,可以先看一下《在Lua中調用C++函數》這篇文章,了解C++中調用Lua的機制。該文中我們将C++中需要導出的函數放到了一個子產品中,其中我們手動的做了一些工作。然而Lua的本質是C,不是C++,Lua提供給C用的API也都是基于面向過程的C函數來用的,要把C++類注冊進Lua形成一個一個的table環境是不太容易一下子辦到的事。為了實作我們的需求,同樣也是官方的需求,在Cocos2d-x 2.x版本的時候,使用的是tolua++這個工具,但是這個工具用起來相當的麻煩,耗費體力,是以現在使用的是bindings-generator工具(官方用Python寫的一個工具),這個東西底層使用的也應該是tolua++。

我沒有使用過tolua++這個工具,不過從網上了解了一下這個工具的使用方法,大緻是這樣的:

1、寫自己的C++類,該怎麼寫就怎麼寫。

2、根據需要導出的C++類的頭檔案寫對應的.pkg檔案,具體怎麼寫得參照tolua++格式。

3、寫一個橋接的類,隻寫它的頭檔案,cpp檔案是使用tolua++工具來生成的,頭檔案具體怎麼寫,也是需要按照tolua++的格式。

4、給這個橋接的類寫一個.pkg檔案。

5、使用指令生成橋接類的.cpp檔案。

6、程式中使用橋接的類,執行一些先關的函數。是以如果使用的是tolua++工具的話,至少需要寫三個檔案,導出類的.pkg檔案,橋接類的.h檔案,橋接類的.pkg檔案,可想而知還是比較麻煩的。現在好了,我們有了bindings-generator工具,下面就來具體的使用一下吧。

1)使用Cocos Code IDE建立一個Lua工程,建立工程的時候記住選中add native code這個選項,這樣會在工程目錄下生成frameworks這個檔案夾,裡邊是C++層的代碼。

2)進入到frameworks的工程目錄下,打開對應的工程,我是在Mac下使用,是以打開的就是Xcode工程。

3)在工程中我們寫自己的類,這個類就是你要導出給Lua層用的接口,實際的需求可能是你一直在c++層寫代碼,某一部分的功能需要在Lua層來實作,這個時候有一些類需要導出給Lua使用,這裡我們隻是模拟一下,寫一個簡單的類好了。

TestLua頭檔案和cpp檔案的内容如下。

#ifndef __Test11__TestLua__

#define __Test11__TestLua__

#include "cocos2d.h"

USING_NS_CC;

class TestLua : public Ref

{

public:

bool init(){return true;};

CREATE_FUNC(TestLua);

int show(int);

};

#endif

#include "TestLua.h"

int TestLua::show(int arg)

{

log("xiaota show %d",arg);

return arg+100;

}

檔案寫好了,這個時候去工程中看一下TestLua的檔案位置,發現不是在Classes目錄下,為了友善操作,我把這倆個檔案複制到了Classes目錄下一份。

4)現在需要做的就是導出這個類的接口給Lua使用了。現在進入工程的frameworks/cocos2d-x/tools/bindings-generator目錄下,仔細閱讀README.md文檔,将必須配置的工具和環境變量配置好。

然後進入tolua目錄,原目錄下隻有genbindings.py,我把這個檔案複制了一份命名為genbindings_xiaota.py,然後複制了一個cocos2dx.ini檔案,重新命名為xiaota.ini。genbindings.py檔案是一個Python腳本,這個腳本在執行的過程中會讀取.ini的配置檔案,然後根據這些個配置檔案生成我們需要的橋接類。

現在我們就來修改一下這倆個重要的檔案,網上有不少的童鞋沒有成功的關鍵大多數是因為這倆個檔案修改的不當所導緻的,是以這一步至關重要!如下圖所示,output_dir是将生成的橋接類放到哪個檔案夾下,我這裡放置的地方和引擎将橋接類放置的地方是相同的,cmd_args是在腳本執行的過程中讀取的配置檔案,我的配置檔案是xiaota.ini,是以第一個參數就是xiaota.ini,其中你看到的lua_xiaota_auto這個東西就是最後生成的橋接類的名字。

genbindings.py檔案還是比較簡單的,我們再來修改xiaota.ini檔案,打開檔案,我們有以下的五處需要修改。中括号中的内容和你檔案名相同,prefix同樣和檔案名相同,主要的是target_namespace,它的值代表的就是子產品名,比如Cocos中的子產品名cc,這裡我使用的子產品名是tt。headers代表的是頭檔案的路徑,我引用的是Classes下的檔案,classes代表的就是類名。如果你有多個檔案,可以參照cocos2d.ini中的寫法去寫,我們寫這個檔案的時候也是複制的官方的檔案,然後在這個基礎上進行的修改,是以,以後不論官方如何變化,複制它的檔案,然後修改這幾個關鍵的地方就好了。

5)接下來就需要使用Python腳本來生成我們的橋接類了,網上不少的同學最後的結果都是失敗,為了排除錯誤,你可以先運作genbindings.py,看看是否成功,如果不成功那麼就是你環境配置的有問題,如果成功再運作自己的Python檔案,不成功的話80%的錯誤都是ini配置檔案沒有配置正确。

編譯成功,我們可以到剛才生成橋接類的檔案夾下看一下這個檔案。

在auto檔案夾下,lua_xiaota_auto.hpp和lua_xiaota_auto.cpp就是我生成的橋接類,在api檔案夾下的TestLua.lua就是導出的LuaAPI。

6)下面我們就使用這個橋接類來将我們的類注冊到Lua環境中。打開AppDelegate.cpp檔案,包含一下橋接類lua_xiaota_auto.hpp,然後在applicationDidFinishLaunching函數中寫如下的代碼。

其中的register_all_xiaota就是用來注冊類的,它是橋接類中的一個比較重要的函數。

7)為了編譯這個橋接類,我們需要将這個新生成的類加入到工程中,右鍵工程添加檔案,添加進來橋接類。這個時候你會發現橋接類的.cpp檔案處說找不到我們自己的類TestLua。是以還需要設定一下search的路徑。

8、經過這些步驟以後基本就算成功了,現在需要打開Cocos Code IDE的工程,重新build一下runtime,跑程式的時候我們使用這個最新的runtime,大家需要明确的一點是當我們改變c++層的代碼的時候就需要重新build一下runtime,說白了就是重新編譯一下c++的檔案,讓Lua腳本運作在一個新的環境下。

9、打開工程的main.lua,在工程中使用導出來的接口,最終來驗證一下是否成功。

local function main()

collectgarbage("collect")

-- avoid memory leak

collectgarbage("setpause", 100)

collectgarbage("setstepmul", 5000)

local val = tt.TestLua:create():show(10)

print(val)

end