1. 程式人生 > >cocos2dx-lua基礎內容之 使用者事件中的觸控事件

cocos2dx-lua基礎內容之 使用者事件中的觸控事件

本篇部落格是描述使用coocs2dx lua 使用觸控事件的演示。關於main.lua的檔案,請從同系列的前面文章中尋找。

基礎的內容將不再講解,本文將講述重點的內容。

使用步驟

  1. 建立需要的監聽器(觸控監聽器,鍵盤監聽器)。
  2. 監聽器設定是否吞沒。
  3. 監聽器設定需要監聽的事件型別(cc.Handler.EVENT_TOUCH_BEGAN),以及對應的回撥函式。
  4. 建立分發器,註冊事件監聽器。

使用案例

size=cc.Director:getInstance():getVisibleSize()

local testScene=class("Test",
        function
()
return cc.Scene:create() end ) --初始化 function testScene:ctor() print("ctor running") end function testScene:create() local scene=testScene.new() --建立場景。 local layer=testScene:createLayer() --建立層。 scene:addChild(layer) --將層新增到場景中
return scene --返回場景 end function testScene:createLayer() local layer=cc.Layer:create() --建立場景 spriteTag=100 local sp=cc.Sprite:create("HelloWorld.png") sp:setPosition(cc.p(size.width/2,size.height/2+200)) layer:addChild(sp,10,spriteTag) spriteTag1=101
local sp1=cc.Sprite:create("HelloWorld.png") sp1:setPosition(cc.p(size.width/2-100,size.height/2+50)) layer:addChild(sp1,10,spriteTag1) --回撥函式的引數依次為觸控物件,以及被繫結的node物件。順序不能錯。 local function touchBegan(touch,event) print("touchBegan") --獲取繫結的Sprite物件,只有使用SceneGraph註冊時有用 local node=event:getCurrentTarget() local pos=node:convertToNodeSpace(touch:getLocation()) local size=node:getContentSize() local rect=cc.rect(0,0,size.width,size.height) --判斷觸控點是否觸控到被監聽的物件。 if cc.rectContainsPoint(rect,pos) then print("pos.x="..pos.x,"pos.y"..pos.y) print("node tag="..node:getTag()) node:runAction(cc.ScaleTo:create(0.5,1.5)) --需要返回true,才能呼叫後面兩個函式。 return true end return false end local function touchEnded(touch,event) print("touchEnded") local node=event:getCurrentTarget() node:runAction(cc.ScaleTo:create(0.5,1.0)) end function touchMoved(touch,event) print("touchMoved") local node=event:getCurrentTarget() local nodeX,nodeY=node:getPosition() local diff=touch:getDelta() node:setPosition(cc.p(nodeX+diff.x,nodeY+diff.y)) end --建立單點觸控監聽器 local listeners=cc.EventListenerTouchOneByOne:create() --設定是否吞沒事件。 listeners:setSwallowTouches(true) --註冊回撥函式以及事件屬性 listeners:registerScriptHandler(touchBegan,cc.Handler.EVENT_TOUCH_BEGAN) listeners:registerScriptHandler(touchMoved,cc.Handler.EVENT_TOUCH_MOVED) listeners:registerScriptHandler(touchEnded,cc.Handler.EVENT_TOUCH_ENDED) --建立事件分發器 local eventDispatcher=cc.Director:getInstance():getEventDispatcher() --監聽器被註冊一次,就無法再次註冊了。可以使用clone()克隆一個同樣的監聽器 listener1=listeners:clone() --精靈物件sp,sp1註冊事件監聽 eventDispatcher:addEventListenerWithSceneGraphPriority(listeners, sp) eventDispatcher:addEventListenerWithSceneGraphPriority(listener1,sp1)

每一個事件監聽器只能被新增一次,addEventListenerWithSceneGraphPriority和addEventListenerWithFixedPriority會在新增事件監聽器時設定一個註冊標識,一旦設定了註冊標識,該監聽器就不能再用於註冊其他事件監聽了,因此需要使用clone()函式獲得一個新的監聽器物件,把這個新的監聽器物件用於註冊。

如何獲取被觸控的物件

當使用addEventListenerWithSceneGraphPriority()註冊監聽器時,可以使用event:getCurrentTarget()獲取被繫結的精靈物件。如:

local function onTouch(touch,event) 
   local node=event:getCurrentTarget()
end

當使用addEventListenerWithFixedPriority()註冊監聽器時,不可以使用event:getCurrentTarget()獲取繫結的精靈物件,因為使用FixedPriority時,根本就沒有繫結的精靈。所以這個時候,只能使用layer:getChildByTag(number)一個一個獲取,然後再判斷。

程式碼如下,添加了一個自定義的isTap(),並且修改了觸控事件的回撥函式:

    --使用Fixed註冊的事件回撥函式案例。
    --自定義判斷觸控點是否在精靈內
    local function isTap(node,touch)
       local size=node:getContentSize()
       local rect=cc.rect(0,0,size.width,size.height)
       local pos=node:convertToNodeSpace(touch:getLocation())
       if cc.rectContainsPoint(rect,pos) then    
          --如果觸控點在精靈內,則返回true。      
          return true
       end

    end

    local function touchBegan(touch,event)
        --使用layer:getChildByTag(tag)獲取一個node。
        --有多少個node需要判斷,就需要獲取多少個node。
        local node1=layer:getChildByTag(spriteTag)
        if isTap(node1,touch) then 
           node1:runAction(cc.ScaleTo:create(0.5,1.5))
           return true
        end

        local node2=layer:getChildByTag(spriteTag1)
        if isTap(node2,touch) then
            node2:runAction(cc.ScaleTo:create(0.5,1.25))
            return true
        end

       return false
    end

    local function touchMoved(touch,event)

       local node1=layer:getChildByTag(spriteTag)
        if isTap(node1,touch) then 
           print("node1 moved")
           local diff=touch:getDelta()
           local nodeX,nodeY=node1:getPosition()
           node1:setPosition(cc.p(nodeX+diff.x,nodeY+diff.y))
            --如果不return一個空值 ,當下麵條件也成立的話,也會執行
            --結果就是兩個精靈一起移動。
           return
        end

        local node2=layer:getChildByTag(spriteTag1)
        if isTap(node2,touch) then
           print("node2222 moved")
           local diff=touch:getDelta()
           local nodeX,nodeY=node2:getPosition()
           node2:setPosition(cc.p(nodeX+diff.x,nodeY+diff.y))
           return
        end
    end
 local eventDispatcher=cc.Director:getInstance():getEventDispatcher()
 --注意這裡使用的是FixedPriority註冊的。
eventDispatcher:addEventListenerWithFixedPriority(listeners, 20)

從上面可以得知,當使用Fixed時,無論是touchBegan,還是touchMoved、touchEnded都需要一個一個獲取需要判斷的精靈物件,然後再使用自定義的方法isTap()一個一個判斷。

注意事項

  1. 首先註冊事件不是註冊在某一個精靈物件上,而是整個螢幕都會有註冊事件。也就是說在整個螢幕都可以觸發touchBegan函式。

  2. 因為整個螢幕都會有註冊事件,所以應該touchBegan預設返回false,這樣touchMove和touchEnded都不會被呼叫。然後在touchBegan中判斷點是否在物件範圍內,存在的話執行對其的操作,然後返回true。

  3. 監聽器物件不是隻能建立一個,可以建立多個。只是當註冊了一個事件監聽器,就不能再進行註冊了,只能使用listener:clone(),還有一個需要注意的是,使用了clone()就沒辦法移除監聽器,因為沒有名字。

  4. 使用FixedPriority listeners時,新增完之後需要手動remove,而使用SceneGraphyPriority listener和Node繫結,當Node銷燬時會被移除。
    _eventDispatcher:removeEventListener(listener);

  5. 移除監聽器的時候,對於listener:clone()的如果不移除,就會一直存在。此時如果在這個監聽器的回撥函式中獲得不到某個精靈時就會報錯。而對於使用listener()->clone的就沒辦法像上面一樣移除了,因為它沒有名字,它只是克隆出來的,除非移除所有的監聽。那麼按鈕的監聽也不能使用了。

  6. 如何獲得精靈物件,並對其執行操作。
    使用SceneGraphPriority註冊事件,可以使用event:getCurrentTarget();獲得繫結的target。
    使用FixtedPriority註冊事件,只能使用layer:getChildByTag(精靈Tag值) 獲得。除非是常量。

  7. 如果需要單獨處理某個物件,就可以考慮使用Fixted,可以針對特定的精靈執行特定的處理。而如果需要對多個物件,做同樣的處理,就可以使用SceneGraphPriority。因為可以在函式處理中使用event:getCurrentTarget() //獲得被繫結的精靈

  8. SceneGraph 把精靈顯示優先順序作為事件優先順序,即addChild()的第二個引數,zOrder值越大,事件優先順序就越大。
    Fixed 指定固定的事件優先順序(第二個引數)註冊監聽器,事件優先順序決定事件響應的優先級別,值越小優先順序越高。