最近做一個(gè)小項目,是用Lua寫(xiě)的,中間用到了很多的回調,基本Cocos中的那幾種常用回調都用到了,本文就針對所用到的回調函數做一個(gè)總結。
1、菜單按鈕的回調
這二者的回調是這么實(shí)現的,新建一個(gè)菜單或者是按鈕,為了點(diǎn)擊菜單或者按鈕以后實(shí)現程序的邏輯,我們需要為菜單和按鈕來(lái)綁定一個(gè)回調函數,于是乎,我們有了以下的代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | --定義菜單項的回調函數 local function item1_callback() --切換場(chǎng)景 local gameScene = require("GameScene") cc.Director:getInstance():replaceScene(gameScene:createScene()) end local function item2_callback() --切換場(chǎng)景 local aboutScene = require("AboutScene") cc.Director:getInstance():pushScene(aboutScene:createScene()) end local item1 = cc.MenuItemLabel:create(cc.Label:createWithTTF("開(kāi)始游戲","fonts/menu.ttf",42)) item1:registerScriptTapHandler(item1_callback) local item2 = cc.MenuItemLabel:create(cc.Label:createWithTTF("關(guān)于游戲","fonts/menu.ttf",42)) item2:registerScriptTapHandler(item2_callback)--創(chuàng )建菜單 local menu = cc.Menu:create(item1,item2) menu:alignItemsVerticallyWithPadding(size.height*0.15)--添加菜單到游戲中 layer:addChild(menu) |
在這里我們使用了一個(gè)重要的回調注冊函數registerScriptTapHandler,Tap就是按下的意思,所以調用這個(gè)函數的時(shí)候是對菜單和按鈕進(jìn)行綁定的,這個(gè)函數的調用者是菜單項,需要傳入一個(gè)參數,這個(gè)參數就是綁定的函數。接下來(lái)我們看下綁定的函數,我綁定的函數并沒(méi)有接受任何傳遞過(guò)來(lái)的參數,這個(gè)就是Lua,你可以選擇接受或者不接受,但是參數就在那里。為了看看這貨是什么鳥(niǎo),我們寫(xiě)上倆個(gè)參數,打印一下,發(fā)現一個(gè)值是-1,一個(gè)值是UserData,有圖為證。
1 2 3 4 5 6 7 | --定義菜單項的回調函數 local function item1_callback(para1,para2) print(para1,para2) --切換場(chǎng)景 local gameScene = require("GameScene") cc.Director:getInstance():replaceScene(gameScene:createScene()) end |

打印的結果是-1和userdata,userdata我們可以理解,你綁定的誰(shuí)那么就傳遞過(guò)來(lái)誰(shuí)嘛,但是第一個(gè)傳遞過(guò)來(lái)的參數是-1腫么回事?原來(lái)第一個(gè)參數代表的是tag,如果你沒(méi)有給你的菜單項設置tag,那么它就是-1,如果設置了tag,那么這個(gè)值就是tag的值,OK,這樣的話(huà)就清楚了。以下的代碼是添加button的代碼,一共添加了三個(gè)button,大家可以參考一下。
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 47 48 49 50 51 52 53 54 55 | --添加按鈕function GameScene:addButton(layer) --創(chuàng )建button local function scale9_normal() return cc.Scale9Sprite:create("buttonBackground.png") end local function scale9_press() return cc.Scale9Sprite:create("buttonHighlighted.png") end --文本信息 self.button1_label = cc.Label:createWithTTF("Ready","fonts/label.TTF",32) self.button2_label = cc.Label:createWithTTF("Ready","fonts/label.TTF",32) self.button3_label = cc.Label:createWithTTF("Ready","fonts/label.TTF",32) --button1 local button1 = cc.ControlButton:create(self.button1_label,scale9_normal()) button1:setBackgroundSpriteForState(scale9_press(),cc.CONTROL_EVENTTYPE_TOUCH_DOWN) button1:setTag(1) button1:setPosition(self.size.width*0.2,self.size.height*0.2) --button2 local button2 = cc.ControlButton:create(self.button2_label,scale9_normal()) button2:setBackgroundSpriteForState(scale9_press(),cc.CONTROL_EVENTTYPE_TOUCH_DOWN) button2:setTag(2) button2:setPosition(self.size.width*0.5,self.size.height*0.2) --button3 local button3 = cc.ControlButton:create(self.button3_label,scale9_normal()) button3:setBackgroundSpriteForState(scale9_press(),cc.CONTROL_EVENTTYPE_TOUCH_DOWN) button3:setTag(3) button3:setPosition(self.size.width*0.8,self.size.height*0.2) --設置button的回調函數 local button_callback = function (ref,button) --如果正確跟新分數 if self.correct == ref:getTag() then self:correct_callback() else self:wrong_callback() end end --設置回調函數 button1:registerControlEventHandler(button_callback,cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE) button2:registerControlEventHandler(button_callback,cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE) button3:registerControlEventHandler(button_callback,cc.CONTROL_EVENTTYPE_TOUCH_UP_INSIDE) --添加到層中 layer:addChild(button1) layer:addChild(button2) layer:addChild(button3)end |
2、添加Android返回鍵的響應代碼
Android返回鍵同樣需要回調函數來(lái)做這件事情,在Cocos中使用的是事件監聽(tīng)和分發(fā)機制,所以我們需要先注冊一下事件類(lèi)型,然后綁定回調,代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | --監聽(tīng)手機返回鍵 local key_listener = cc.EventListenerKeyboard:create() --返回鍵回調 local function key_return() --結束游戲 cc.Director:getInstance():endToLua() end --lua中得回調,分清誰(shuí)綁定,監聽(tīng)誰(shuí),事件類(lèi)型是什么 key_listener:registerScriptHandler(key_return,cc.Handler.EVENT_KEYBOARD_RELEASED) local eventDispatch = layer:getEventDispatcher() eventDispatch:addEventListenerWithSceneGraphPriority(key_listener,layer) |
這次我們使用的注冊回調函數是registerScriptHandler,沒(méi)有Tap,顯然就不是為菜單和按鈕回調準備的,所以這個(gè)函數是用來(lái)注冊一般的回調函數所使用的。其中注釋有句話(huà)說(shuō)的比較好,就是一定要明白誰(shuí)綁定,監聽(tīng)誰(shuí),事件類(lèi)型是什么,在這個(gè)例子看來(lái),是事件監聽(tīng)器去綁定了一個(gè)回調函數key_return,然后事件的類(lèi)型是放到了一個(gè)Handler表中的,我們的事件類(lèi)型是keyBoard,可以到Handler中看看都有哪些事件類(lèi)型,然后所有你熟悉的東西都會(huì )看到了,比如以下的代碼所代表的事件類(lèi)型。
1 2 3 4 5 6 | local listener = cc.EventListenerTouchOneByOne:create()listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )local eventDispatcher = layerFarm:getEventDispatcher()eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layerFarm) |
3、動(dòng)作的回調
3.x以后在C++層的動(dòng)作回調函數只剩下Callfunc和CallfuncN了,其他的都可以用c++11的std::bind解決,而在Lua中就剩下一個(gè)了,這個(gè)是由Lua的特性決定的,用法如下。
1 2 3 4 5 6 7 8 | --ready和go的回調函數 函數可以有倆個(gè)參數,第一個(gè)代表接受動(dòng)作的對象,就是誰(shuí)執行了動(dòng)作,第二個(gè)是傳過(guò)來(lái)的參數,全部放到了表中local ready_action = function(actionSelf,tab)endlocal go_action = function()endcc.CallFunc:create(ready_action,{x=1}) |
CallFunc中有倆個(gè)參數,一個(gè)是綁定的回調函數,另一個(gè)是table表,這個(gè)表中可以存放一些命名參數,把你想要傳遞的東西統統通過(guò)這個(gè)表傳遞過(guò)去,然后在回調函數中,我們有倆個(gè)參數來(lái)接受,第一個(gè)當然是動(dòng)作的執行者了,第二個(gè)就是傳遞過(guò)來(lái)的這張表,里邊有所有我們要得參數,是不是很高大上??!
4、小結
看完了以上的這些東西,我們基本明白了怎么使用,所謂知其然更要知其所以然,這些回調函數是怎么分發(fā)到Lua層的代碼中的,我們就需要看一個(gè)文件了。打開(kāi)你引擎目錄的cocos/scripting/lua-bindings/manual/CCLuaEngine.cpp文件,我們需要找到這樣一處代碼。
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | int LuaEngine::sendEvent(ScriptEvent* evt){ if (NULL == evt) return 0; switch (evt->type) { case kNodeEvent: { return handleNodeEvent(evt->data); } break; case kMenuClickedEvent: { return handleMenuClickedEvent(evt->data); } break; case kCallFuncEvent: { return handleCallFuncActionEvent(evt->data); } break; case kScheduleEvent: { return handleScheduler(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; case kCommonEvent: { return handleCommonEvent(evt->data); } break; case kControlEvent: { return handlerControlEvent(evt->data); } break; default: break; } return 0;} |
sendEvent顧名思義,這段代碼就是向Lua層來(lái)分發(fā)回調事件的代碼,在這段代碼中,我們看到了很多熟悉的身影,比如說(shuō)node的分發(fā),menu的分發(fā),schedule的分發(fā),touch的分發(fā)等等都在這里,但是卻沒(méi)有事件監聽(tīng)器的分發(fā),沒(méi)錯,事件監聽(tīng)器的回調Lua并沒(méi)有寫(xiě)在這個(gè)文件中,而是在其他的文件中處理的,大家可以自行研究。我們以node回調Lua層的代碼為例,看看是怎么回調Lua層的函數的,關(guān)鍵的代碼在這里:
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 | int action = *((int*)(basicScriptData->value)); switch (action) { case kNodeOnEnter: _stack->pushString("enter"); break; case kNodeOnExit: _stack->pushString("exit"); break; case kNodeOnEnterTransitionDidFinish: _stack->pushString("enterTransitionFinish"); break; case kNodeOnExitTransitionDidStart: _stack->pushString("exitTransitionStart"); break; case kNodeOnCleanup: _stack->pushString("cleanup"); break; default: return 0; } int ret = _stack->executeFunctionByHandler(handler, 1); _stack->clean(); |
根據action的類(lèi)型,我們將不同的字符串壓入了棧中,然后執行了executeFunctionByHandler函數,第一個(gè)參數handler就是回調的函數,第二個(gè)參數代表傳遞到回調函數中的參數個(gè)數。其他的回調Lua層的函數大同小異,大家自行研究吧。那么在Lua層,這個(gè)回調函數是怎么被注冊的呢?我們新建工程由系統創(chuàng )建了一個(gè)GameScene.lua文件,這個(gè)文件中的這段代碼,不知道大家是否留意過(guò)。
1 2 3 4 5 6 | local function onNodeEvent(event) if "exit" == event then cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.schedulerID) endendlayerFarm:registerScriptHandler(onNodeEvent) |
所以以后Lua中實(shí)現onEnter,onExit函數知道怎么做了吧,本文就到這里了。
推薦閱讀:
來(lái)源網(wǎng)址:http://www.zaojiahua.com/lua-callback-functions.html
聯(lián)系客服