1. 程式人生 > >Quick-Cocos2d-x遊戲開發觸控捕獲事件 cc.NODE_TOUCH_CAPTURE_EVENT

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對於捕獲事件的原理了。