quick-cocos2d-x遊戲開發【10】——觸摸捕獲事件 cc.NODE_TOUCH_CAPTURE_EVENT

如果看過sample中touch的代碼,你會發現示例中有一個cc.NODE_TOUCH_CAPTURE_EVENT事件,它和cc.NODE_TOUCH_EVENT觸摸事件一樣,是引擎級別的事件,我們來看看它和觸摸事件的區別。


首先觸摸捕獲事件默認是開啓的,即setTouchCaptureEnabled(true)


觸摸捕獲事件的優先級要比觸摸事件要高,換句話說,觸摸捕獲事件會比觸摸事件先響應,並且有權不分發給觸摸事件響應。

對於一個完整的捕獲+觸摸事件,有這麼一個流程:

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中,我們來看下結果,

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

觸摸吞噬都關閉,各個事件返回值都是true,print的結果是,


因爲sprite後添加,他們在同一個zOrder上所以sprite要靠前,先捕獲到事件,然後到觸摸事件,做完之後傳遞到下面的layer,layer開始捕獲然後處理觸摸事件。


這就是quick對於捕獲事件的原理了。如有錯誤,歡迎指出。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章