Quick-Cocos2d-x遊戲開發觸控捕獲事件 cc.NODE_TOUCH_CAPTURE_EVENT
如果看過sample中touch的程式碼,你會發現示例中有一個cc.NODE_TOUCH_CAPTURE_EVENT事件,它和cc.NODE_TOUCH_EVENT觸控事件一樣,是引擎級別的事件,我們來看看它和觸控事件的區別。
觸控捕獲事件的優先順序要比觸控事件要高,換句話說,觸控捕獲事件會比觸控事件先響應,並且有權不分發給觸控事件響應。
對於一個完整的捕獲+觸控事件,有這麼一個流程:
1. 捕獲階段,一旦有觸控事件發生,那麼首先會觸發捕獲事件,並且捕獲順序是從zOrder高到低,越在螢幕上方越優先捕獲。從父節點傳到子節點,父節點優先捕獲。
2. 目標階段,該階段就是各個節點響應自己的觸控事件,began,moved,ended等。
3. 傳遞階段,只要當前節點沒有將觸控吞噬,那麼觸控事件將會繼續往下層的節點進行傳送。
有了一些理論知識,我們來實際操作一下,寫些程式碼:
function MyScene:ctor() local layer = display.newLayer() self:addChild(layer) layer:setTouchEnabled(true) layer:setTouchSwallowEnabled(false) layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event) if event.name == "began" then print("layer began") elseif event.name == "moved" then print("layer moved") elseif event.name == "ended" then print("layer ended") end return true end) layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event) if event.name == "began" then print("layer capture began") elseif event.name == "moved" then print("layer capture moved") elseif event.name == "ended" then print("layer capture ended") end return true end) local sp = display.newSprite("HelloWorld.png", display.cx, display.cy) layer:addChild(sp) --self:addChild(sp) sp:setTouchEnabled(true) sp:setTouchSwallowEnabled(false) sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event) if event.name == "began" then print("sp began") elseif event.name == "moved" then print("sp moved") elseif event.name == "ended" then print("sp ended") end return true end) sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event) if event.name == "began" then print("sp capture began") elseif event.name == "moved" then print("sp capture moved") elseif event.name == "ended" then print("sp capture ended") end return true end) end
程式碼中,添加了兩個節點,一個是layer,一個sprite,sprite新增在layer上,他們都開啟了觸控,沒有吞噬觸控,並且添加了捕獲事件和觸控事件,返回值為true。簡單點選一下視窗,看看print資訊,
因為父節點會優先捕獲事件,所以首先是layer捕獲到了,其次子節點捕獲到,接下來是處理觸控,因為子節點在父節點的上面,所以子節點先響應了觸控事件,處理過後由於沒有吞噬觸控,所以會繼續將觸控事件向下傳遞,此時它的下面就是它的父節點laier,所以layer又再一次捕獲到了這個事件,最後layer開始響應觸控事件。
如果我們將子節點sprite設定吞噬觸控,
可以看到,當sprite響應了觸控事件之後就不再向下傳遞了,所以父節點就不能再捕獲到上方傳下來的觸摸了。
我們再修改一下程式碼,把layer的捕獲事件返回為false,sprite還是依然保持吞噬觸控,也就是在之前的程式碼上做這樣的修改,
layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("layer capture began")
elseif event.name == "moved" then
print("layer capture moved")
elseif event.name == "ended" then
print("layer capture ended")
end
return false
end)
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
layer:addChild(sp)
--self:addChild(sp)
sp:setTouchEnabled(true)
--sp:setTouchSwallowEnabled(false)
sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
我們執行一下,點選螢幕看下效果,
這裡我是擡起了滑鼠後截出來的日誌資訊,可以看到,layer的捕獲開始列印了兩次。
由於我們在父節點layer的捕獲事件中,將其設定成返回false,所以其子節點是無法響應後面的觸控事件的,但是關鍵的是,即便父節點在捕獲階段阻止響應事件,但子物件仍然可以捕獲到事件,只是不會觸發事件,說白了就是,父節點阻斷了捕獲,但是我子節點依然可以捕獲到,只是子節點的捕獲不響應各個事件,也不會再讓後面的觸控事件響應。
所以我們回過來想一下,第一次觸控式螢幕幕,父節點捕獲到了,子節點也捕獲到了,但是返回false,所以子節點的捕獲事件不觸發,所以看不到sprite打出捕獲資訊,並且sprite也不響應觸控事件,所以吞不吞噬也就沒作用了,繼續分發著走,那麼layer就會再一次捕獲到自己的事件,只是這次返回的false,它把它自己的後面的觸控事件也停止了。所以ended事件響應我們一個都看不到。
不知道大家有沒有理清思路,這次我們不把sprite新增在layer上,sprite也新增在scene中,我們來看下結果,
local layer = display.newLayer()
self:addChild(layer)
layer:setTouchEnabled(true)
layer:setTouchSwallowEnabled(false)
layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("layer began")
elseif event.name == "moved" then
print("layer moved")
elseif event.name == "ended" then
print("layer ended")
end
return true
end)
layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("layer capture began")
elseif event.name == "moved" then
print("layer capture moved")
elseif event.name == "ended" then
print("layer capture ended")
end
return true
end)
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
--layer:addChild(sp)
self:addChild(sp)
sp:setTouchEnabled(true)
sp:setTouchSwallowEnabled(false)
sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
if event.name == "began" then
print("sp began")
elseif event.name == "moved" then
print("sp moved")
elseif event.name == "ended" then
print("sp ended")
end
return true
end)
sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)
if event.name == "began" then
print("sp capture began")
elseif event.name == "moved" then
print("sp capture moved")
elseif event.name == "ended" then
print("sp capture ended")
end
return true
end)
end
觸控吞噬都關閉,各個事件返回值都是true,print的結果是,
因為sprite後新增,他們在同一個zOrder上所以sprite要靠前,先捕獲到事件,然後到觸控事件,做完之後傳遞到下面的layer,layer開始捕獲然後處理觸控事件。
這就是Quick對於捕獲事件的原理了。