【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对于捕获事件的原理了。若有错误,欢迎指出。