【cocos2d-x从c++到js】回调函数1——按键回调
发布时间:2020-12-14 17:10:26 所属栏目:百科 来源:网络整理
导读:回调函数是界面交互和接入各种第三方SDK的关键所在,因为回调函数的C++代码是不能自动生成的,一切的一切,都需要手写完成。 比较不错的是,Cocos2d-x引擎对于回调函数提供了完整的包装机制。我们所需要做的就是了解这个机制,并使用他。学习引擎自己的代码
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
// "create" in JS
// cc.MenuItemImage.create( normalImage,selectedImage,[disabledImage],callback_fn,[this]
JSBool js_cocos2dx_CCMenuItemImage_create(JSContext *cx,uint32_t argc,jsval *vp)
{
if
(argc >= 2 && argc <= 5) {
jsval *argv = JS_ARGV(cx,vp);
JSStringWrapper arg0(argv[0]);
JSStringWrapper arg1(argv[1]);
JSStringWrapper arg2;
bool
thirdArgIsString =
true
;
jsval jsCallback = JSVAL_VOID;
jsval jsThis = JSVAL_VOID;
int
last = 2;
(argc >= 3) {
thirdArgIsString = argv[2].isString();
(thirdArgIsString) {
arg2.set(argv[2],cx);
last = 3;
}
}
cocos2d::MenuItemImage* ret = cocos2d::MenuItemImage::create(arg0.get(),arg1.get(),std::string(arg2.get()));
(argc >= 3) {
(!thirdArgIsString) {
//cc.MenuItemImage.create( normalImage,[this] )
jsCallback = argv[last++];
(argc == 4) {
jsThis = argv[last];
}
}
else
{
jsCallback = argv[last++];
(argc == 5) {
jsThis = argv[last];
}
}
}
}
JSObject *obj = bind_menu_item<cocos2d::MenuItemImage>(cx,ret,jsCallback,jsThis);
JS_SET_RVAL(cx,vp,OBJECT_TO_JSVAL(obj));
return
JS_TRUE;
}
JS_ReportError(cx,
"Invalid number of arguments. Expecting: 2 <= args <= 5"
);
JS_FALSE;
}
|
18
(argc >= 3) {
(!thirdArgIsString) {
jsCallback = argv[last++];
(argc == 4) {
jsThis = argv[last];
}
}
{
(argc >= 4) {
jsCallback = argv[last++];
(argc == 5) {
jsThis = argv[last];
}
}
}
在这里我们从参数中取出回调函数和this,分别赋值给jsCallback和jsThis。
1
由这句模板函数来实现回调的绑定,四个参数依次是,JS上下文,cc.MenuItemImage对应的C++对象,回调函数,和回调函数调用时的this。
17
<
class
T>
JSObject* bind_menu_item(JSContext *cx,T* nativeObj,jsval callback,jsval thisObj) {
js_proxy_t *p = jsb_get_native_proxy(nativeObj);
(p) {
addCallBackAndThis(p->obj,callback,thisObj);
p->obj;
}
{
js_type_class_t *classType = js_get_type_from_native<T>(nativeObj);
assert
(classType);
JSObject *tmp = JS_NewObject(cx,classType->jsclass,classType->proto,classType->parentProto);
// bind nativeObj <-> JSObject
js_proxy_t *proxy = jsb_new_proxy(nativeObj,tmp);
JS_AddNamedObjectRoot(cx,&proxy->obj,
typeid
(*nativeObj).name());
addCallBackAndThis(tmp,thisObj);
tmp;
}
继续看bind_menu_item的实现。简单说一下,因为绑定的是一个JS函数,所以实际上,需要在SpiderMonkey里面做这个绑定操作。传进来的是一个C++对象(CCMenuItemImage类型),首先找到和这个C++对象对应的JS对象。如果找不到,就新建立一个。然后通过函数addCallBackAndThis执行绑定。
9
static void addCallBackAndThis(JSObject *obj,jsval &thisObj)
{
if
(callback != JSVAL_VOID) {
ScriptingCore::getInstance()->setReservedSpot(0,obj,callback);
}
(thisObj != JSVAL_VOID) {
ScriptingCore::getInstance()->setReservedSpot(1,thisObj);
}
4
JS_SetReservedSlot(obj,i,value);
JS_TRUE;
最终我们看到,存储回调函数的方法是通过SpiderMonkey的ReservedSlot机制。0位存放的是回调函数,1位存放的是回调函数对应的this。
17
MenuItem::activate()
{
(_enabled)
( _callback )
{
_callback(
this
);
(kScriptTypeNone != _scriptType)
{
BasicScriptData data(
);
ScriptEvent scriptEvent(kMenuClickedEvent,&data);
ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent);
非常简单,首先判断按键是否可用。然后如果有C++层回调就调用。如果有脚本层(JS或lua)回调,就包装一个kMenuClickedEvent事件,然后向对应的脚本引擎发送该事件。
45
(NULL == evt)
return
0;
JSAutoCompartment ac(_cx,_global);
switch
(evt->type)
{
case
kNodeEvent:
{
handleNodeEvent(evt->data);
}
break
;
kMenuClickedEvent:
{
handleMenuClickedEvent(evt->data);
}
;
kTouchEvent:
{
handleTouchEvent(evt->data);
}
;
kTouchesEvent:
{
handleTouchesEvent(evt->data);
}
;
kKeypadEvent:
{
handleKeypadEvent(evt->data);
}
;
kAccelerometerEvent:
{
handleAccelerometerEvent(evt->data);
}
;
default
:
;
}
0;
JS通过ScriptingCore::sendEvent进行事件分发。kMenuClickedEvent事件派发给handleMenuClickedEvent函数来处理。
20
(NULL == data)
BasicScriptData* basicScriptData = static_cast<BasicScriptData*>(data);
(NULL == basicScriptData->nativeObject)
0;
MenuItem* menuItem = static_cast<MenuItem*>(basicScriptData->nativeObject);
js_proxy_t * p = jsb_get_native_proxy(menuItem);
(!p)
0;
jsval retval;
jsval dataVal;
js_proxy_t *proxy = jsb_get_native_proxy(menuItem);
dataVal = (proxy ? OBJECT_TO_JSVAL(proxy->obj) : JSVAL_NULL);
executeJSFunctionFromReservedSpot(
->_cx,p->obj,dataVal,retval);
1;
14
executeJSFunctionFromReservedSpot(JSContext *cx,
jsval &dataVal,jsval &retval) {
jsval func = JS_GetReservedSlot(obj,0);
(func == JSVAL_VOID) {
; }
jsval thisObj = JS_GetReservedSlot(obj,1);
JSAutoCompartment ac(cx,obj);
(thisObj == JSVAL_VOID) {
JS_CallFunctionValue(cx,func,1,&dataVal,&retval);
{
(!JSVAL_IS_PRIMITIVE(thisObj));
}
再次通过SpiderMonkey的ReservedSlot机制,取回相应的参数,最后通过JS_CallFunctionValue函数完成JS层回调函数的调用。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!