[cocos2dx-JSB篇]使用JSB-Binding(自動綁定篇)

文章撰寫日期︰2013/09/09 12:20
文章更新日期︰2014/01/20 11:27
文章更新次數︰5
本篇cocos2dx使用版本︰v 2.1.4

一、前言

使用Javascript攢寫遊戲,
在Web、Android、IOS和Win32平臺同步發佈已成為開發趨勢。
但由於Javascript在cocos2dx裡是被包裝後的頂層語言,
仍然需要不定時跟下面的C++溝通。

如果EasyJSB套件已經無法滿足您簡單的跨語言溝通需求,
那麼,
Zynga團隊寫岀來的Javascript自動編譯工具cxx-generator
也就是在cocos2dx\tools裡看到的bindings-generator,
肯定符合您的需要。

透過此工具,
讓我們能快速的將C++ native code,
自動編譯讓JS端能夠呼叫並使用。

cocos2d-x在Javascript這邊使用的是蜘蛛猴子(SpiderMonkey),它是Firefox用來執行Javascript的JS虛擬機器(VM)。
這套虛擬機器也被拿來給cocos2d支援使用,在重力引擎Chipmunk和CocosBuilder Reader Api等套件都看的到相關應用。當你在JS裡create一個CCSprite時,你就是實際在C++建立一個CCSprite。當你在JS建立了一個action,也是實際在C++建立了一個action。粒子系統...等等的都是這個概念。
用這個方法來編譯估算大概比使用HTML5還快10~20倍。
雖然說基本上使用JS來執行Chipmunk和CocosBuilder Reader APIs幾乎跟native執行已經是等同的執行速度,但還是有幾件事是我們該注意的︰

  • 當JS在執行garbage collector時,執行效能可能會慢下來。解決辦法︰不要執行過多的JS物件,盡可能的重覆使用它們。
  • 倘若使用了一個複雜的main loop(執行緒循環),也可能降低效能。解決辦法︰規劃好你的JS code,直到你不能再優化它為止。或者做一些額外的effort像使用C++與JS綁定那些你需要的功能。

二、文章開始

開始使用Binding-generator工具

第1步 確認好你的Binding-generator

cocos2d-x下載下來後,tools目錄底下已經有一個名為bindings-generator的工具就是。
如果仍需下載,請至github。
GitHub repository: https://github.com/cocos2d/bindings-generator

第2步 安裝Apple的Command Line Developer Tool

這個工具是在Xcode裡安裝的。

[Xcode]-->[Preference]-->[Downloads]-->選擇[Command Line Tools]-->Install

第3步 同意Xcode License

在timernal底下打
xcodebuild -license
照著步驟同意。

第4步 下載MacPorts

MacPorts是一個很方便的工具,能讓你透過指令的方式就下載到各式各樣的程式。
為了下載Phyton,我們必須先下載MacPorts。
位址在︰
http://www.macports.org/install.php

註︰
如果你已經使用了另一套工具Homebrew,最好先移除它。因為Homebrew無法和MacPorts共處的很好。

第5步 更新MacPorts至最新版

$sudo port -v selfupdate 
註︰如果找不到port指令,代表您環境變數沒設定好。
請爬文處理相關問題。

第6步 使用指令下載安裝python27

$sudo port install python27 py27-yaml py27-cheetah

會看到像下面的畫面︰

第7步 安裝llvm-3.3

請到http://llvm.org/releases/download.html#3.3下載,
注意下載的檔案是這個︰
下載完後請解壓至Users/你的名字/bin底下,
並將解壓岀來的資料夾更名成clang+llvm-3.3。
如果沒有bin資料夾,請自行創建。
最後的路徑名稱應該會長成這樣︰
/Users/lp43/bin/clang+llvm-3.3(lp43是我的名稱)

第8步 安裝Android NDK r8e

提供mac版下載位址
http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2

第9步 配置設定

客製化cocos2dx\tools\bindings-generator\test裡的userconf.ini和user.cfg檔。
你會看到預設後面還有.sample的副檔名,把它們拿掉

並將userconf.ini裡面的值改成這樣︰
[DEFAULT]
androidndkdir=/Users/lp43/Android/adt-bundle-mac/android-ndk-r8e
clangllvmdir=/Users/lp43/bin/clang+llvm-3.3
cxxgeneratordir=/Users/lp43/cocos2d-x3.0/tools/bindings-generator
androidndkdir放置您android ndk下載解壓後的存放路徑
clangllvmdir放置您剛才clang+llvm下載後的解壓存放路徑
cxxgeneratordir存放您cocos2dx-bindings-generator工具的存放路徑

而user.cfg改成這樣
[DEFAULT]
PYTHON_BIN=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
如果您剛才有用macPorts安裝Phython,那麼Phython的存放路徑就會是在上面這個路徑。

第10步 替test定義target_namespace

到cocos2dx\tools\bindings-generator\test底下,
更改test.ini裡
target_namespace =ts
這個動作目的是告訴Javascript我們有一個C++ native的code會被掛到SpiderMonkey裡使用,
辨識代碼(tag)我們取名叫ts

第11步 編譯與啟用bindings-generator

Terminal裡,我們在test目錄下,打上︰
./test.sh

如果以上的動作您都有做, 那麼應該會看到


(筆者註︰如果編譯上遇到一些問題或困難,
請參考文章最下方的問題與回答是否有提供您答案。)

不要理會編譯過程中製造岀來的Warning,
接著你會看到build岀來的3個檔案被放在資料夾中,
它們分別是︰
  • 一個.hpp標頭檔,用來綁定類別用的
  • 一個.cpp檔,實作了上面的綁定類別
  • 一個.js檔,它是一份文件,用來教你怎麼從Javascript呼叫你剛才欲使用、用Natvie C++寫岀來的函式

建置JsBinding-HelloWorld專案並啟用

使用Xcode建置一個cocos2dx-js專案
將剛才bindings-generator工具編譯岀來的2個資料夾simple_Test和simple_test_binding放進專案底下Classes底下(記住要用Create groups for any added folders的方式將程式導入Xcode,不要用Create folder references for any added folders,否則會遇到Undefined symbols for architecture i386:
  "register_all_
autogentestbindings(JSContext*, JSObject*)", referenced from: AppDelegate::applicationDidFinishLaunching() in AppDelegate.o的錯誤)
如果您剛才第10步驟沒有做,
那麼就要再到autogentestbindings.cpp裡將register_all_autogentestbindings(JSContext* cx, JSObject* obj)函式做修改
Errors in parsing headers:
void register_all_autogentestbindings(JSContext* cx, JSObject* obj) {
    jsval nsval;
    JSObject *ns;
    JS_GetProperty(cx, obj, "ts",&nsval);
    if (nsval == JSVAL_VOID) {
        ns = JS_NewObject(cx, NULL, NULL, NULL);
        nsval = OBJECT_TO_JSVAL(ns);
        JS_SetProperty(cx, obj, "ts",&nsval);
    } else {
        JS_ValueToObject(cx,nsval, &ns);
    }
    obj = ns;
    js_register_autogentestbindings_SimpleNativeClass(cx, obj);
} 
否則上面這段是能省略的。

向SpiderMonkey註冊您有自己寫了一個Native C++。

在AppDelegate.cpp裡,
include autogentestbindings.hpp。

#include "simple_test_bindings/autogentestbindings.hpp"

添加剛才製作岀來的callback︰
sc->addRegisterCallback(register_all_autogentestbindings); 

在hello.js裡var GameCreateor = function(){};裡
添加下面的code做測試︰
            var myClass=new ts.SimpleNativeClass();
            var myStr=myClass.returnsACString();
            var label2 = cc.LabelTTF.create(myStr, "Helvetica", 20.0);
            label2.setPosition(cc.p(winSize.width/2, winSize.height/3));
            layer.addChild(label2,1);

此時, 應該就能看到畫面如下圖了︰
圖中看到的this is a c-string haha就是C++端的函式,
已經成功被我們用JS的方式呼叫了。

三、問題與回答

附上一些在編譯與產生binding code(上面文章 第11步)時可能遇到的 Q and A。

  1. Error: Unable to open port: can't read "build.cmd": Failed to locate 'make' in path: '/opt/local/bin:/opt/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin' or at its MacPorts configuration time location, did you move it?
    這個問題會發生的原因是因為您沒有安裝Command Line Tools,請參照上面第2步完成安裝動作。
  2. dlsym(0x7f99a30f7b80, clang_getFieldDeclBitWidth): symbol not found. Please ensure that your python bindings are compatible with your libclang.so version.
    這個問題造成的原因是clang+llvm檔案下載錯了,請參照上面第7步下載正確的clang+llvm檔。
  3. Error parsing translation unit.
  4. 這個問題造成的原因是編譯需要的檔案或工具有缺少。
    可能是︰userconf.ini檔裡cxxgeneratordir路徑指定錯誤了,也可能是需要煸譯的檔案有遺失或不完整造成(如test目錄裡simple_test原始C++檔目錄被你刪掉導致缺少了欲編譯檔案而無法完成編譯) 

文章參考來源︰

1. 老G的Blog
2. cocos2d-x官方教學
3. cocos2d-x論壇

文章關鍵字︰
cocos2d-x, Javascript call C++, Javascript call Native, JSB Binding, cxx-generator, bindings-generator

沒有留言 :

張貼留言