本篇博客是描述使用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);扫描二维码关注公众号,回复: 1631015 查看本文章移除监听器的时候,对于listener:clone()的如果不移除,就会一直存在。此时如果在这个监听器的回调函数中获得不到某个精灵时就会报错。而对于使用listener()->clone的就没办法像上面一样移除了,因为它没有名字,它只是克隆出来的,除非移除所有的监听。那么按钮的监听也不能使用了。
如何获得精灵对象,并对其执行操作。
使用SceneGraphPriority注册事件,可以使用event:getCurrentTarget();获得绑定的target。
使用FixtedPriority注册事件,只能使用layer:getChildByTag(精灵Tag值) 获得。除非是常量。如果需要单独处理某个对象,就可以考虑使用Fixted,可以针对特定的精灵执行特定的处理。而如果需要对多个对象,做同样的处理,就可以使用SceneGraphPriority。因为可以在函数处理中使用event:getCurrentTarget() //获得被绑定的精灵
SceneGraph 把精灵显示优先级作为事件优先级,即addChild()的第二个参数,zOrder值越大,事件优先级就越大。
Fixed 指定固定的事件优先级(第二个参数)注册监听器,事件优先级决定事件响应的优先级别,值越小优先级越高。