cocos2dx-js 绑定c++

5 篇文章 0 订阅
2 篇文章 0 订阅

最近在倒腾c++绑定方法到js,供js调用。在此记录一下,供交流和学习。

coscos2dx有很多版本,例如cocos2dx-js, -lua版本。使用脚本语言进行协同开发,好处之一就提现在版本升级方面。当修改了逻辑之后,只需要替换本地的响应脚本代码即可。省去了一下审核流程。

这里说说c++绑定到js,供js调用c++方法。

  主要用到的几个宏:

用于声明的宏:

<p class="p1"><span class="s1">#define JS_BINDED_CLASS_GLUE(klass) \</span></p><p class="p1"><span class="s1">static JSClass js_class; \</span></p><p class="p1"><span class="s1">static JSObject* js_proto; \</span></p><p class="p1"><span class="s1">static JSObject* js_parent; \</span></p><p class="p1"><span class="s1">static void _js_register(JSContext* cx, JS::HandleObject global);</span></p>
JS_BINDED_CLASS_GLUE,这个宏主要定义了3个变量和1个方法。

js_class初始化比较固定:

JSClass jsclass = {
        "方法名", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
<span style="white-space:pre">		</span> JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,basic_object_finalize
    };

其中basic_object_finalize,一般为该类的销毁方法。功能类似析构函数。



js_proto初始化需要调用方法: JS_InitClass

JavaScriptObjCBridge::js_proto = JS_InitClass(cx, global, JS::NullPtr(), &JavaScriptObjCBridge::js_class , JavaScriptObjCBridge::_
<span style="white-space:pre">						</span>js_constructor, 0, props, funcs, NULL, NULL);
js_parent初始化直接设置为NULL就行。


方法:void_js_register(JSContext *cx, JS::HandleObject global)

该方法供js引擎调用,这里面主要的工作就初始化函数调用列表。


<span style="font-family: Arial, Helvetica, sans-serif;">#define JS_BINDED_CONSTRUCTOR(klass) \</span>
static bool _js_constructor(JSContext *cx, unsigned argc, jsval *vp)

该方法主要用来对需要注册到js的类进行初始化。初始化的工作内容包括,js_proto,js_parent这个两个变量的初始化,并把加入js引擎里面去。供js调用。


#define JS_BINDED_FUNC(klass, name) \
bool name(JSContext *cx, unsigned argc, jsval *vp)
该宏主要定义需要绑定到js的方法名。有一个对应的实现方法:

#define JS_BINDED_FUNC_IMPL(klass, name) \
static bool klass##_func_##name(JSContext *cx, unsigned argc, jsval *vp) { \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
JS::RootedObject thisObj(cx, args.thisv().toObjectOrNull()); \
klass* obj = (klass*)JS_GetPrivate(thisObj); \
if (obj) { \
return obj->name(cx, argc, vp); \
} \
JS_ReportError(cx, "Invalid object call for function %s", #name); \
return false; \
} \
bool klass::name(JSContext *cx, unsigned argc, jsval *vp)
判断传过来的参数是否为空,如果不为空,调用name这个方法。此处获取参数的方式与以往版本有所不同。

之前获取参数的方式:JS_ARGV这个宏,实际就是把vp这个指针偏移2.

现在获取参数的方式:通过方法:JS::CallArgsFromvp(argc,vp).


下面以一个简单的例子,删除无关代码。

.h
class JavaScriptObjCBridge{
public:
    JS_BINDED_CLASS_GLUE(JSObjCBridge);
    JS_BINDED_CONSTRUCTOR(JSObjCBridge);
    JS_BINDED_FUNC(JSObjCBridge, callStaticMethod);
};


.cpp
/**
 *  @brief Initialize Object and needed properties.
 *
 */
JS_BINDED_CLASS_GLUE_IMPL(JavaScriptObjCBridge);

/**
 *  @brief Implementation for the Javascript Constructor
 *
 */
JS_BINDED_CONSTRUCTOR_IMPL(JavaScriptObjCBridge)
{
    JavaScriptObjCBridge* jsj = new (std::nothrow) JavaScriptObjCBridge();
    
    js_proxy_t *p;
    jsval out;
    
    JS::RootedObject proto(cx, JavaScriptObjCBridge::js_proto);
    JS::RootedObject parentProto(cx, JavaScriptObjCBridge::js_parent);
    JS::RootedObject obj(cx, JS_NewObject(cx, &JavaScriptObjCBridge::js_class, proto, parentProto));
    
    if (obj) {
        JS_SetPrivate(obj, jsj);
        out = OBJECT_TO_JSVAL(obj);
    }
    
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    args.rval().set(out);
    p = jsb_new_proxy(jsj, obj);
    
    JS::AddNamedObjectRoot(cx, &p->obj, "JavaScriptObjCBridge");
    return true;
}

/**
 *  @brief destructor for Javascript
 *
 */
static void basic_object_finalize(JSFreeOp *freeOp, JSObject *obj)
{
    CCLOG("basic_object_finalize %p ...", obj);
    
    js_proxy_t* nproxy;
    js_proxy_t* jsproxy;
    JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
    JS::RootedObject jsobj(cx, obj);
    jsproxy = jsb_get_js_proxy(jsobj);
    if (jsproxy) {
        nproxy = jsb_get_native_proxy(jsproxy->ptr);
        jsb_remove_proxy(nproxy, jsproxy);
    }
}
<p class="p1"><span class="s1">JS_BINDED_FUNC_IMPL</span><span class="s2">(</span><span class="s3">JavaScriptObjCBridge</span><span class="s2">, callStaticMethod){</span></p><p class="p1"><span class="s2">    </span><span class="s3">JS</span><span class="s2">::</span><span class="s3">CallArgs</span><span class="s2"> args = </span><span class="s3">JS</span><span class="s2">::</span><span class="s3">CallArgsFromVp</span><span class="s2">(argc, vp);</span></p><p class="p1"><span class="s2">    </span><span class="s1">if</span><span class="s2"> (argc >= 2) {</span></p><p class="p1"><span class="s2">        </span><span class="s3">JSStringWrapper</span><span class="s2"> arg0(args.</span><span class="s3">get</span><span class="s2">(0));</span></p><p class="p1"><span class="s2">        </span><span class="s3">JSStringWrapper</span><span class="s2"> arg1(args.</span><span class="s3">get</span><span class="s2">(1));</span></p><p class="p1"><span class="s2">        </span><span class="s3">CallInfo</span><span class="s2"> call(arg0.</span><span class="s3">get</span><span class="s2">(),arg1.</span><span class="s3">get</span><span class="s2">());</span></p><p class="p1"><span class="s2">        </span><span class="s1">bool</span><span class="s2"> ok = call.</span><span class="s3">execute</span><span class="s2">(cx,args.</span><span class="s3">array</span><span class="s2">(),argc);</span></p><p class="p1"><span class="s2">        </span><span class="s1">if</span><span class="s2">(!ok){</span></p><p class="p2"><span class="s4">            </span><span class="s3">JS_ReportError</span><span class="s4">(cx, </span><span class="s2">"js_cocos2dx_JSObjCBridge : call result code: %d"</span><span class="s4">, call.</span><span class="s3">getErrorCode</span><span class="s4">());</span></p><p class="p1"><span class="s2">            </span><span class="s1">return</span><span class="s2"> </span><span class="s1">false</span><span class="s2">;</span></p><p class="p1"><span class="s2">        }</span></p><p class="p3"><span class="s4">        args.</span><span class="s2">rval</span><span class="s4">().</span><span class="s2">set</span><span class="s4">(</span><span class="s2">convertReturnValue</span><span class="s4">(cx, call.</span><span class="s2">getReturnValue</span><span class="s4">(), call.</span><span class="s2">getReturnValueType</span><span class="s4">()));</span></p><p class="p1"><span class="s2">        </span><span class="s1">return</span><span class="s2"> ok;</span></p><p class="p1"><span class="s2">    }</span></p><p class="p4"><span class="s4">    </span><span class="s2">return</span><span class="s4"> </span><span class="s2">false</span><span class="s4">;</span></p><p class="p1"><span class="s2">}</span></p>

<p class="p1"><span class="s1">/**</span></p><p class="p1"><span class="s1"> *  @brief register JavascriptJavaBridge to be usable in js</span></p><p class="p1"><span class="s1"> *</span></p><p class="p1"><span class="s1"> */</span></p><p class="p2"><span class="s2">void</span><span class="s3"> </span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::_js_register(</span><span class="s1">JSContext</span><span class="s3"> *cx, </span><span class="s1">JS</span><span class="s3">::</span><span class="s1">HandleObject</span><span class="s3"> global)</span></p><p class="p3"><span class="s1">{</span></p><p class="p3"><span class="s1">    </span><span class="s4">JSClass</span><span class="s1"> jsclass = {</span></p><p class="p2"><span class="s3">        </span><span class="s5">"JavaScriptObjCBridge"</span><span class="s3">, </span><span class="s2">JSCLASS_HAS_PRIVATE</span><span class="s3">, </span><span class="s1">JS_PropertyStub</span><span class="s3">, </span><span class="s1">JS_DeletePropertyStub</span><span class="s3">, </span><span class="s1">JS_PropertyStub</span><span class="s3">, </span><span class="s1">JS_StrictPropertyStub</span><span class="s3">, </span><span class="s1">JS_EnumerateStub</span><span class="s3">, </span><span class="s1">JS_ResolveStub</span><span class="s3">, </span><span class="s1">JS_ConvertStub</span><span class="s3">,</span><span class="s1">basic_object_finalize</span></p><p class="p3"><span class="s1">    };</span></p><p class="p4"><span class="s1">    </span></p><p class="p2"><span class="s3">    </span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::</span><span class="s1">js_class</span><span class="s3"> = jsclass;</span></p><p class="p3"><span class="s1">    </span><span class="s2">static</span><span class="s1"> </span><span class="s4">JSPropertySpec</span><span class="s1"> props[] = {</span></p><p class="p5"><span class="s3">        </span><span class="s1">JS_PSG</span><span class="s3">(</span><span class="s5">"__nativeObj"</span><span class="s3">, </span><span class="s4">js_is_native_obj</span><span class="s3">, </span><span class="s1">JSPROP_PERMANENT</span><span class="s3"> | </span><span class="s1">JSPROP_ENUMERATE</span><span class="s3"> ),</span></p><p class="p5"><span class="s3">        </span><span class="s1">JS_PS_END</span></p><p class="p3"><span class="s1">    };</span></p><p class="p4"><span class="s1">    </span></p><p class="p3"><span class="s1">    </span><span class="s2">static</span><span class="s1"> </span><span class="s4">JSFunctionSpec</span><span class="s1"> funcs[] = {</span></p><p class="p3"><span class="s1">        </span><span class="s2">JS_BINDED_FUNC_FOR_DEF</span><span class="s1">(JavaScriptObjCBridge, callStaticMethod),</span></p><p class="p5"><span class="s3">        </span><span class="s1">JS_FS_END</span></p><p class="p3"><span class="s1">    };</span></p><p class="p4"><span class="s1">    </span></p><p class="p2"><span class="s3">    </span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::</span><span class="s1">js_parent</span><span class="s3"> = </span><span class="s2">NULL</span><span class="s3">;</span></p><p class="p2"><span class="s3">    </span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::</span><span class="s1">js_proto</span><span class="s3"> = </span><span class="s1">JS_InitClass</span><span class="s3">(cx, global, </span><span class="s1">JS</span><span class="s3">::</span><span class="s1">NullPtr</span><span class="s3">(), &</span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::</span><span class="s1">js_class</span><span class="s3"> , </span><span class="s1">JavaScriptObjCBridge</span><span class="s3">::</span><span class="s1">_js_constructor</span><span class="s3">, 0, props, funcs, </span><span class="s2">NULL</span><span class="s3">, </span><span class="s2">NULL</span><span class="s3">);</span></p><p class="p3"><span class="s1">}</span></p><p class="p4"><span class="s1"></span>
</p>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值