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?日誌
local layer = display.newLayer() code
self:addChild(layer) xml
layer:setTouchEnabled(true) htm
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)
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?
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
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?
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: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?
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
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對於捕獲事件的原理了。若有錯誤,歡迎指出。