cocos2dx-lua基礎內容之 使用者事件中的觸控事件
本篇部落格是描述使用coocs2dx lua 使用觸控事件的演示。關於main.lua的檔案,請從同系列的前面文章中尋找。
基礎的內容將不再講解,本文將講述重點的內容。
使用步驟
- 建立需要的監聽器(觸控監聽器,鍵盤監聽器)。
- 監聽器設定是否吞沒。
- 監聽器設定需要監聽的事件型別(cc.Handler.EVENT_TOUCH_BEGAN),以及對應的回撥函式。
- 建立分發器,註冊事件監聽器。
使用案例
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()一個一個判斷。
注意事項
首先註冊事件不是註冊在某一個精靈物件上,而是整個螢幕都會有註冊事件。也就是說在整個螢幕都可以觸發touchBegan函式。
因為整個螢幕都會有註冊事件,所以應該touchBegan預設返回false,這樣touchMove和touchEnded都不會被呼叫。然後在touchBegan中判斷點是否在物件範圍內,存在的話執行對其的操作,然後返回true。
監聽器物件不是隻能建立一個,可以建立多個。只是當註冊了一個事件監聽器,就不能再進行註冊了,只能使用listener:clone(),還有一個需要注意的是,使用了clone()就沒辦法移除監聽器,因為沒有名字。
使用FixedPriority listeners時,新增完之後需要手動remove,而使用SceneGraphyPriority listener和Node繫結,當Node銷燬時會被移除。
_eventDispatcher:removeEventListener(listener);移除監聽器的時候,對於listener:clone()的如果不移除,就會一直存在。此時如果在這個監聽器的回撥函式中獲得不到某個精靈時就會報錯。而對於使用listener()->clone的就沒辦法像上面一樣移除了,因為它沒有名字,它只是克隆出來的,除非移除所有的監聽。那麼按鈕的監聽也不能使用了。
如何獲得精靈物件,並對其執行操作。
使用SceneGraphPriority註冊事件,可以使用event:getCurrentTarget();獲得繫結的target。
使用FixtedPriority註冊事件,只能使用layer:getChildByTag(精靈Tag值) 獲得。除非是常量。如果需要單獨處理某個物件,就可以考慮使用Fixted,可以針對特定的精靈執行特定的處理。而如果需要對多個物件,做同樣的處理,就可以使用SceneGraphPriority。因為可以在函式處理中使用event:getCurrentTarget() //獲得被繫結的精靈
SceneGraph 把精靈顯示優先順序作為事件優先順序,即addChild()的第二個引數,zOrder值越大,事件優先順序就越大。
Fixed 指定固定的事件優先順序(第二個引數)註冊監聽器,事件優先順序決定事件響應的優先級別,值越小優先順序越高。