中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

【cocos2d-x從c++到js】09:JS與C++的交互1——JS代碼調用C++代碼

發布時間:2020-07-19 23:11:51 來源:網絡 閱讀:12471 作者:老G 欄目:游戲開發

之前我們講過,在游戲啟動時,我們要通過SpiderMonkey引擎的注冊接口,向SpiderMonkey注冊相應的從C++到JS的綁定函數,這些函數用于把JS函數調用代碼轉換成對應C++函數調用來執行。


//在AppDelegate::applicationDidFinishLaunching函數中
    ScriptingCore* sc = ScriptingCore::getInstance();
    sc->addRegisterCallback(register_all_cocos2dx);
    sc->addRegisterCallback(register_all_cocos2dx_extension);
    sc->addRegisterCallback(register_cocos2dx_js_extensions);
    sc->addRegisterCallback(register_all_cocos2dx_extension_manual);
    sc->addRegisterCallback(jsb_register_chipmunk);
    sc->addRegisterCallback(JSB_register_opengl);
    sc->addRegisterCallback(jsb_register_system);
    sc->addRegisterCallback(MinXmlHttpRequest::_js_register);
    sc->addRegisterCallback(register_jsb_websocket);
    sc->addRegisterCallback(register_all_cocos2dx_builder);
    sc->addRegisterCallback(register_CCBuilderReader);
    sc->addRegisterCallback(register_all_cocos2dx_gui);
    sc->addRegisterCallback(register_all_cocos2dx_gui_manual);
    sc->addRegisterCallback(register_all_cocos2dx_studio);
    sc->addRegisterCallback(register_all_cocos2dx_studio_manual);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    sc->addRegisterCallback(register_all_cocos2dx_spine);


可以看到上面導入了Cocos2d-x的各種庫,核心庫,擴展,opengl,物理引擎,websocket,CCB等等等等。


下面我們說JS代碼如何調用C++代碼。

首先,在創建JS對象的時候,也會創建一個對應的C++對象。換句話說,JS對象是和C++對象一一對應的(當然必須是引擎支持的,而且綁定了接口的)。然后,在JS對象執行函數時,發生了什么呢?SpiderMonkey引擎會通過注冊的接口,找到對應的C++對象,調用該對象上對應的C++函數。


換句話說,如果有下面的JS代碼:

var node = cc.Node.create();
node.setVisible(false);


那么經過SpiderMonkey執行后,會調用下面的代碼:

auto node = CCNode::create();
node->setVisible(false);


當然,SpiderMonkey遠遠還不止干了這些,還做了很多事,比如綁定和查找JS和C++對象的對應關系,包裝參數為對應類型,類型安全檢查,返回值包裝等等。要知道他干了些什么,直接看引擎代碼是更好的選擇。


在Cocos2d-x 3.0版的引擎中,引擎目錄結構進行了大規模重構。

【cocos2d-x從c++到js】09:JS與C++的交互1——JS代碼調用C++代碼

兩個腳本語言被放到一個類似的目錄中。其中auto-generated/js-bindings文件夾是gxx-generator工具自動生成的所有C++綁定JS代碼。而javascript/bingdings文件夾是手寫的綁定代碼,因為工具無法做到完全自動綁定,所以必須有一部分手寫的(腳本語言都是這樣,習慣就好了,謝謝)。


好,我們繼續找剛才說的源代碼。打開jsb_cocos2dx_auto.cpp

   
JSBool js_cocos2dx_Node_create(JSContext *cx, uint32_t argc, jsval *vp)
{
    if (argc == 0) {
        cocos2d::Node* ret = cocos2d::Node::create();
        jsval jsret = JSVAL_NULL;
        do {
        if (ret) {
            js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::Node>(cx, (cocos2d::Node*)ret);
            jsret = OBJECT_TO_JSVAL(proxy->obj);
        } else {
            jsret = JSVAL_NULL;
        }
    } while (0);
        JS_SET_RVAL(cx, vp, jsret);
        return JS_TRUE;
    }
    JS_ReportError(cx, "js_cocos2dx_Node_create : wrong number of arguments");
    return JS_FALSE;
}


這就是cc.Node.create()執行時,底層C++跑的代碼。所有的通過JS調用C++的代碼都與這個形式非常一致,首先看函數接口:

第一個參數JSContext *cx是JS的上下文

第二個參數uint32_t argc是JS代碼中的參數個數,在這個里argc==0

第三個參數jsval *vp是JS代碼中的具體參數


繼續分析

cocos2d::Node* ret = cocos2d::Node::create();

這個代碼再熟悉不過了,標準的Cocos2d-x靜態工場生成對象的代碼


jsval jsret = JSVAL_NULL;

jsval jsret是這個函數的返回值,這是表示的是一個JS對象


js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::Node>(cx, (cocos2d::Node*)ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);

注意這個模板函數,get_or_create,這就是把JS對象和C++對象綁到一起的函數。他非常重要,注意JS和C++對象是一一對應關系,理解這個特效,有助于我們利用JS語言的動態性進行更方便的編程。綁完之后,下面那個函數是用于獲得返回值。


最后,函數都要返回一個JSBool,表面這個函數執行是否成功。如果返回JS_FALSE,還會通過JS_ReportError打印一條報錯信息。注意!腳本語言有一個特點,如果函數運行失敗了,則該函數后面的函數(在同一作用域中的)都會跳過執行。


繼續看下一個函數

JSBool js_cocos2dx_Node_setVisible(JSContext *cx, uint32_t argc, jsval *vp)
{
    jsval *argv = JS_ARGV(cx, vp);
    JSBool ok = JS_TRUE;
    JSObject *obj = JS_THIS_OBJECT(cx, vp);
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    cocos2d::Node* cobj = (cocos2d::Node *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, JS_FALSE, "js_cocos2dx_Node_setVisible : Invalid Native Object");
    if (argc == 1) {
        JSBool arg0;
        ok &= JS_ValueToBoolean(cx, argv[0], &arg0);
        JSB_PRECONDITION2(ok, cx, JS_FALSE, "js_cocos2dx_Node_setVisible : Error processing arguments");
        cobj->setVisible(arg0);
        JS_SET_RVAL(cx, vp, JSVAL_VOID);
        return JS_TRUE;
    }
    JS_ReportError(cx, "js_cocos2dx_Node_setVisible : wrong number of arguments: %d, was expecting %d", argc, 1);
    return JS_FALSE;
}

這個函數和前一個函數的區別是,這個函數有參數,并且他是一個類成員函數(上一個是類靜態函數),所以,這里要有this指針。

jsval *argv = JS_ARGV(cx, vp);
JSBool ok = JS_TRUE;
JSObject *obj = JS_THIS_OBJECT(cx, vp);
js_proxy_t *proxy = jsb_get_js_proxy(obj);
cocos2d::Node* cobj = (cocos2d::Node *)(proxy ? proxy->ptr : NULL);
JSB_PRECONDITION2( cobj, cx, JS_FALSE, "js_cocos2dx_Node_setVisible : Invalid Native Object");

這一大段函數都在找那個this指針。注意,這里面有一個Cocos2d-x引擎經常出現的錯誤提示Invalid Native Object。底層C++對象被回收了,所以找不到了。


if (argc == 1) {
    JSBool arg0;
    ok &= JS_ValueToBoolean(cx, argv[0], &arg0);
    JSB_PRECONDITION2(ok, cx, JS_FALSE, "js_cocos2dx_Node_setVisible : Error processing arguments");
    cobj->setVisible(arg0);
    JS_SET_RVAL(cx, vp, JSVAL_VOID);
    return JS_TRUE;
}

CCNode::setVisible(xx)只有一個參數,所以先判斷JS的參數個數為1。JS_ValueToBoolean完成JS對象到C++對象的轉換,注意!這是基本類型的轉換,和查找對應的對象指針不同。你在gxx-generator生成的代碼中會看到大量的這種轉換。每次轉換都要進行結果判斷,如果失敗,就打印錯誤信息。后面是直接調用對應C++對象的setVisible,以及設置返回值。


很繁瑣不是嗎?如果這種代碼全部手寫是不是會死人呢。肯定的吧。所以這些代碼都是用腳本生成器做出來的(絕大部分)。



后面我們會繼續講解各種JS的綁定代碼。



向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

巴南区| 柘荣县| 壶关县| 泸西县| 乃东县| 揭东县| 定陶县| 武安市| 枣阳市| 皮山县| 郯城县| 内江市| 通化市| 贵港市| 崇信县| 奉化市| 安福县| 新密市| 金川县| 得荣县| 汕尾市| 大新县| 郴州市| 平顶山市| 石门县| 紫金县| 固镇县| 兴化市| 尤溪县| 河曲县| 汉源县| 海安县| 广平县| 边坝县| 嘉禾县| 科技| 筠连县| 克东县| 汝州市| 施秉县| 河间市|