【quick-cocos2d-x】單點觸摸與touch事件

http://blog.csdn.net/w337198302/article/details/38909295html

http://blog.csdn.net/w337198302/article/details/38920945ide

 

quick的觸摸機制,我想廖大已經在這篇文章裏說的很清楚了,咱們這些小輩們就是在他的基礎上完備一下,說說用法就能夠了,嘿嘿。函數


在2.2.3以前的版本(不包括2.2.3),觸摸機制和廖大在那篇文章裏面的說的同樣,添加觸摸響應採用addTouchEventListener來完成,不過在此以後,對觸摸機制就進行了徹底的改寫,和cocos2dx 3.0的版本同樣,採用更加靈活的CCNode事件分發機制。ui


若是你對cocos 3.0中觸摸機制很瞭解,那麼quick的觸摸使用起來也很方便。直接來看怎麼用。spa

在前面已經說了,咱們添加的節點元素都是在scene中的,可是觸摸響應不能直接給scene添加事件監聽,因此咱們能夠用一個層來完成。而且,若是可以接受觸摸響應,還須要開啓觸摸功能。.net

 

[html] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片日誌

  1. local layer = display.newLayer()  code

  2. self:addChild(layer)  xml

  3. layer:setTouchEnabled(true)  htm

  4. layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

  5. layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)  

  6.     local x, y, prevX, prevY = event.x, event.y, event.prevX, event.prevY  

  7.   

  8.     if event.name == "began" then  

  9.          print("layer began")  

  10.     elseif event.name == "moved" then  

  11.         print("layer moved")  

  12.     elseif event.name == "ended" then  

  13.          print("layer ended")  

  14.     end  

  15.   

  16.     return true  

  17. end)  

    local layer = display.newLayer()
    self:addChild(layer)
    layer:setTouchEnabled(true)
    layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)
    layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)
        local x, y, prevX, prevY = event.x, event.y, event.prevX, event.prevY

        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)


從上面的代碼能夠看到,能夠設置觸摸的模式,

 

cc.TOUCH_MODE_ONE_BY_ONE 是單點觸摸

cc.TOUCH_MODE_ALL_AT_ONCE 是多點觸摸


在添加節點事件監聽addNodeEventListener中,咱們設置監聽事件的類型是cc.NODE_TOUCH_EVENT

這個監聽事件類型,其定義了幾個引擎級事件,分別是,

-- cocos2dx 引擎級事件
c.NODE_EVENT                                           = 0
c.NODE_ENTER_FRAME_EVENT           = 1
c.NODE_TOUCH_EVENT                          = 2
c.NODE_TOUCH_CAPTURE_EVENT     = 3
c.MENU_ITEM_CLICKED_EVENT            = 4
c.ACCELERATE_EVENT                            = 5
c.KEYPAD_EVENT                                       = 6


其次是event參數,在event參數裏,裏面有name,x,y,prevX,prevY 這五個變量,分別表明着

-- event.name 是觸摸事件的狀態:began, moved, ended, cancelled, added(僅限多點觸摸), removed(僅限多點觸摸)
-- event.x, event.y 是觸摸點當前位置
-- event.prevX, event.prevY 是觸摸點以前的位置


因此添加上面的代碼,簡單觸摸屏幕,就能夠看到log中的print的結果。


在觸摸的回調函數function(event)中,記得考慮是否須要添加返回值,返回值的做用不用多說,true則後面的moved,ended等狀態會接收到,不然接收不到,默認若是不添加則表明false。


在新版觸摸機制中,還須要主要的一個就是觸摸吞噬,

setTouchSwallowEnabled(true)

它的做用就是是否繼續傳遞觸摸消息,在繪製節點的時候,越是在屏幕上方,就是zOrder越大,越優先接收到觸摸事件,若是設置吞噬,那麼在它下方的節點都不會接收到觸摸消息了。默認若是不設置則quick自動設置爲true。


固然,不單單能夠給layer添加觸摸事件,你也能夠給精靈添加,這就看你遊戲的須要了。

 

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


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


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

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

1.捕獲階段,一旦有觸摸事件發生,那麼首先會觸發捕獲事件,而且捕獲順序是從zOrder高到低,越在屏幕上方越優先捕獲。從父節點傳到子節點,父節點優先捕獲。

2.目標階段,該階段就是各個節點響應本身的觸摸事件,began,moved,ended等。

3傳遞階段,只要當前節點沒有將觸摸吞噬,那麼觸摸事件將會繼續往下層的節點進行傳送。


有了一些理論知識,咱們來實際操做一下,寫些代碼,

 

[html] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. function MyScene:ctor()   

  2.   

  3.     local layer = display.newLayer()  

  4.     self:addChild(layer)  

  5.     layer:setTouchEnabled(true)  

  6.     layer:setTouchSwallowEnabled(false)  

  7.     layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

  8.     layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)  

  9.         if event.name == "began" then  

  10.              print("layer began")  

  11.         elseif event.name == "moved" then  

  12.             print("layer moved")  

  13.         elseif event.name == "ended" then  

  14.              print("layer ended")  

  15.         end  

  16.   

  17.         return true  

  18.     end)  

  19.   

  20.     layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)  

  21.         if event.name == "began" then  

  22.             print("layer capture began")  

  23.         elseif event.name == "moved" then  

  24.             print("layer capture moved")  

  25.         elseif event.name == "ended" then  

  26.             print("layer capture ended")  

  27.         end  

  28.   

  29.         return true  

  30.     end)  

  31.   

  32.     local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)  

  33.     layer:addChild(sp)  

  34.     --self:addChild(sp)  

  35.     sp:setTouchEnabled(true)  

  36.     sp:setTouchSwallowEnabled(false)  

  37.     sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

  38.     sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)  

  39.         if event.name == "began" then  

  40.             print("sp began")  

  41.         elseif event.name == "moved" then  

  42.             print("sp moved")  

  43.         elseif event.name == "ended" then  

  44.             print("sp ended")  

  45.         end  

  46.   

  47.         return true  

  48.     end)  

  49.   

  50.     sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)  

  51.         if event.name == "began" then  

  52.             print("sp capture began")  

  53.         elseif event.name == "moved" then  

  54.             print("sp capture moved")  

  55.         elseif event.name == "ended" then  

  56.             print("sp capture ended")  

  57.         end  

  58.   

  59.         return true  

  60.     end)  

  61.       

  62. end  

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仍是依然保持吞噬觸摸,也就是在以前的代碼上作這樣的修改,

 

[html] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)  

  2.     if event.name == "began" then  

  3.         print("layer capture began")  

  4.     elseif event.name == "moved" then  

  5.         print("layer capture moved")  

  6.     elseif event.name == "ended" then  

  7.         print("layer capture ended")  

  8.     end  

  9.   

  10.     return false  

  11. end)  

  12.   

  13. local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)  

  14. layer:addChild(sp)  

  15. --self:addChild(sp)  

  16. sp:setTouchEnabled(true)  

  17. --sp:setTouchSwallowEnabled(false)  

  18. sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

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

 

[html] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. function MyScene:ctor()   

  2.   

  3.     local layer = display.newLayer()  

  4.     self:addChild(layer)  

  5.     layer:setTouchEnabled(true)  

  6.     layer:setTouchSwallowEnabled(false)  

  7.     layer:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

  8.     layer:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)  

  9.         if event.name == "began" then  

  10.              print("layer began")  

  11.         elseif event.name == "moved" then  

  12.             print("layer moved")  

  13.         elseif event.name == "ended" then  

  14.              print("layer ended")  

  15.         end  

  16.   

  17.         return true  

  18.     end)  

  19.   

  20.     layer:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)  

  21.         if event.name == "began" then  

  22.             print("layer capture began")  

  23.         elseif event.name == "moved" then  

  24.             print("layer capture moved")  

  25.         elseif event.name == "ended" then  

  26.             print("layer capture ended")  

  27.         end  

  28.   

  29.         return true  

  30.     end)  

  31.   

  32.     local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)  

  33.     --layer:addChild(sp)  

  34.     self:addChild(sp)  

  35.     sp:setTouchEnabled(true)  

  36.     sp:setTouchSwallowEnabled(false)  

  37.     sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE)  

  38.     sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function (event)  

  39.         if event.name == "began" then  

  40.             print("sp began")  

  41.         elseif event.name == "moved" then  

  42.             print("sp moved")  

  43.         elseif event.name == "ended" then  

  44.             print("sp ended")  

  45.         end  

  46.   

  47.         return true  

  48.     end)  

  49.   

  50.     sp:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function (event)  

  51.         if event.name == "began" then  

  52.             print("sp capture began")  

  53.         elseif event.name == "moved" then  

  54.             print("sp capture moved")  

  55.         elseif event.name == "ended" then  

  56.             print("sp capture ended")  

  57.         end  

  58.   

  59.         return true  

  60.     end)  

  61.       

  62. end  

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對於捕獲事件的原理了。若有錯誤,歡迎指出。