您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關cocos2d-x中回調函數的按鍵回調是怎樣的,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
回調函數是界面交互和接入各種第三方SDK的關鍵所在,因為回調函數的C++代碼是不能自動生成的,一切的一切,都需要手寫完成。
比較不錯的是,Cocos2d-x引擎對于回調函數提供了完整的包裝機制。我們所需要做的就是了解這個機制,并使用他。學習引擎自己的代碼例子,可以比較快速準確的上手這一機制。
首先,我們在Cocos2d-x 3.0 beta版中,使用他自帶的工程創建工具,新建一個跨平臺的JS項目。按照慣例,這是一個helloworld項目。在XCode運行時,我們可以看到右下角的回調按鈕。我們來看看他是怎么實現的。分成兩個過程來做:
一、綁定回調函數過程
首先,我們要去找回調函數JS的綁定代碼,在myApp.js中,init函數里面,可以看到如下代碼:
1 2 3 4 5 6 7 8 9 10 11 12 | // var closeItem "res/CloseNormal.png" , "res/CloseSelected.png" , function () cc.log( "close ); }, this ); closeItem.setAnchorPoint(cc.p(0.5, var menu menu.setPosition(cc.p(0, this .addChild(menu, closeItem.setPosition(cc.p(size.width |
cc.MenuItemImage.create函數的第三個參數,綁定了匿名回調函數。第四個參數,傳入的是回調函數調用時的this(如果不理解JS的this機制,請先閱讀一些JS的資料)。這些都是意圖和作用很明顯的JS代碼,不用細說。
然后,我們去看底層對應執行的C++代碼。在cocos2d_specifics.cpp文件中,找到js_cocos2dx_CCMenuItemImage_create函數。
1 2 3 4 5 6 7 8 9 10 11 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 | // // JSBool { if (argc jsval JSStringWrapper JSStringWrapper JSStringWrapper bool thirdArgIsString true ; jsval jsval int last if (argc thirdArgIsString if (thirdArgIsString) arg2.set(argv[2], last } } cocos2d::MenuItemImage* if (argc if (!thirdArgIsString) //cc.MenuItemImage.create( jsCallback if (argc jsThis } } else { //cc.MenuItemImage.create( if (argc jsCallback if (argc jsThis } } } } JSObject JS_SET_RVAL(cx, return JS_TRUE; } JS_ReportError(cx, "Invalid ); return JS_FALSE; } |
因為在C++層,這是一個重載過的函數,所以他的實現里面有很多參數個數的判斷(關于重載問題請參考之前的章節)。過濾掉很多代碼,我們直接看關鍵部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | if (argc if (!thirdArgIsString) //cc.MenuItemImage.create( jsCallback if (argc jsThis } } else { //cc.MenuItemImage.create( if (argc jsCallback if (argc jsThis } } } } |
在這里我們從參數中取出回調函數和this,分別賦值給jsCallback和jsThis。
1 | JSObject |
由這句模板函數來實現回調的綁定,四個參數依次是,JS上下文,cc.MenuItemImage對應的C++對象,回調函數,和回調函數調用時的this。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | template < class T> JSObject* js_proxy_t if (p) addCallBackAndThis(p->obj, return p->obj; } else { js_type_class_t assert (classType); JSObject // js_proxy_t JS_AddNamedObjectRoot(cx, typeid (*nativeObj).name()); addCallBackAndThis(tmp, return tmp; } } |
繼續看bind_menu_item的實現。簡單說一下,因為綁定的是一個JS函數,所以實際上,需要在SpiderMonkey里面做這個綁定操作。傳進來的是一個C++對象(CCMenuItemImage類型),首先找到和這個C++對象對應的JS對象。如果找不到,就新建立一個。然后通過函數addCallBackAndThis執行綁定。
1 2 3 4 5 6 7 8 9 | static { if (callback ScriptingCore::getInstance()->setReservedSpot(0, } if (thisObj ScriptingCore::getInstance()->setReservedSpot(1, } } |
1 2 3 4 | JSBool JS_SetReservedSlot(obj, return JS_TRUE; } |
最終我們看到,存儲回調函數的方法是通過SpiderMonkey的ReservedSlot機制。0位存放的是回調函數,1位存放的是回調函數對應的this。
好,到此為止,回調函數的綁定全部結束。
二、調用回調函數過程
現在我們看從C++層啟動JS回調的過程。我們省略掉事件派發機制,直接看按鍵事件發生時的調用代碼。在按鍵事件發生時,會調用MenuItemImage的父類MenuItem中的activate函數。該函數在CCMenuItem.cpp中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void MenuItem::activate() { if (_enabled) { if ( { _callback( this ); } if (kScriptTypeNone { BasicScriptData this ); ScriptEvent ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&scriptEvent); } } } |
非常簡單,首先判斷按鍵是否可用。然后如果有C++層回調就調用。如果有腳本層(JS或lua)回調,就包裝一個kMenuClickedEvent事件,然后向對應的腳本引擎發送該事件。
1 2 3 4 5 6 7 8 9 10 11 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 | int { if (NULL return 0; JSAutoCompartment switch (evt->type) { case kNodeEvent: { return handleNodeEvent(evt->data); } break ; case kMenuClickedEvent: { return handleMenuClickedEvent(evt->data); } break ; case kTouchEvent: { return handleTouchEvent(evt->data); } break ; case kTouchesEvent: { return handleTouchesEvent(evt->data); } break ; case kKeypadEvent: { return handleKeypadEvent(evt->data); } break ; case kAccelerometerEvent: { return handleAccelerometerEvent(evt->data); } break ; default : break ; } return 0; } |
JS通過ScriptingCore::sendEvent進行事件分發。kMenuClickedEvent事件派發給handleMenuClickedEvent函數來處理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | int { if (NULL return 0; BasicScriptData* if (NULL return 0; MenuItem* js_proxy_t if (!p) return 0; jsval jsval js_proxy_t dataVal executeJSFunctionFromReservedSpot( this ->_cx, return 1; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | static void executeJSFunctionFromReservedSpot(JSContext jsval jsval if (func return ; jsval JSAutoCompartment if (thisObj JS_CallFunctionValue(cx, } else { assert (!JSVAL_IS_PRIMITIVE(thisObj)); JS_CallFunctionValue(cx, } } |
再次通過SpiderMonkey的ReservedSlot機制,取回相應的參數,最后通過JS_CallFunctionValue函數完成JS層回調函數的調用。
關于cocos2d-x中回調函數的按鍵回調是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。