Conflicting "touch" Event Listeners

Hello,

I just started learning LUA this week, and I have started to program a 2D side-scroller game. In this game, the player’s character is moved by pressing buttons displayed on the screen much like a virtual game pad. These buttons work perfectly, however, the problem is that I have a

Runtime:addEventListener("tap", onScreenTap)

event listener that then calls the shoot() function to fire a projectile from the player whenever a tap is registered. This results in a projectile firing every time I lift the touch from one of the movement buttons.

Is there any way I can stop the shoot function from calling when I finish touching one of the movement keys? I have tried 

display.getCurrentStage:setFocus()

and also putting return true at the end of the movement functions but nothing seems to work.

Thanks

Hi Tony,

Tap events don’t behave quite the same with “return true” like touch events do. For your game, especially since firing is probably a quick and repetitive user action, I suggest you use a touch listener with the “began” phase wrap. This will give the user an instant touch-fire reaction, instead of requiring both the touch down-then-up of a tap.

Hope this helps,

Brent Sorrentino

Hey Brent,

Thanks for the reply. I ended up following your advice and instead of using a tap listener I am now using a touch listener with an if statement checking for the “began” phase. However, I still cannot seem to solve my previous problem with the conflicting listeners. Now, the player shoots a projectile every time the user starts pressing a movement button instead of firing on the end of the touch.

Here are the snippets of my code regarding the issue, (sorry for disorganization)

 --move right local moveRightBtn = display.newImage("rightArrow.png") moveRightBtn:setReferencePoint(display.BottomRightReferencePoint) moveRightBtn.x = display.contentWidth moveRightBtn.y = display.contentHeight function moveRightBtn:touch(event) if event.phase == "began" then motionX = walkingSpeed elseif event.phase == "ended" or event.phase == "cancelled" then motionX = 0 return true end end moveRightBtn:addEventListener("touch", moveRightBtn) --move left local moveLeftBtn = display.newImage("leftArrow.png") moveLeftBtn:setReferencePoint(display.BottomRightReferencePoint) moveLeftBtn.x = display.contentWidth - 100 moveLeftBtn.y = display.contentHeight function moveLeftBtn:touch(event) if event.phase == "began" then --display.getCurrentStage():setFocus(event.target) motionX = -walkingSpeed elseif event.phase == "ended" or event.phase == "cancelled" then motionX = 0 return true end end moveLeftBtn:addEventListener("touch", moveLeftBtn) --motion formula local function movePlayer(event) player.x = player.x + motionX end Runtime:addEventListener("enterFrame", movePlayer) --function that shoots projectiles from the player local function shoot(event) if gameState == 1 then if event.phase == "began" then local bullet = display.newCircle(0, 0, 5) bullet:setFillColor(0,100,200) bullet.x = player.x bullet.y = player.y physics.addBody(bullet) bullet.name = 'bullet' bullet.collision = onCollision bullet:addEventListener("collision", bullet) audio.play(soundBlast) transition.to(bullet, {time=1000, x=display.contentWidth+500}) return true end end return true --to stop conflicting with other taps end --Function to process screen tapping local function onScreenTap(event) if event.phase == "began" shoot(event) return true end end Runtime:addEventListener("touch", onScreenTap) --shoot function called on tap

Hi Tony,

Try un-nesting your “return true” lines from inside the “phase” conditions. Put them at the end of the core function(s), so all phases return true.

Thanks Brent!

I un-nested the return true lines and it worked like a charm. Now I can finally move on, thanks.

Hi Tony,

Tap events don’t behave quite the same with “return true” like touch events do. For your game, especially since firing is probably a quick and repetitive user action, I suggest you use a touch listener with the “began” phase wrap. This will give the user an instant touch-fire reaction, instead of requiring both the touch down-then-up of a tap.

Hope this helps,

Brent Sorrentino

Hey Brent,

Thanks for the reply. I ended up following your advice and instead of using a tap listener I am now using a touch listener with an if statement checking for the “began” phase. However, I still cannot seem to solve my previous problem with the conflicting listeners. Now, the player shoots a projectile every time the user starts pressing a movement button instead of firing on the end of the touch.

Here are the snippets of my code regarding the issue, (sorry for disorganization)

 --move right local moveRightBtn = display.newImage("rightArrow.png") moveRightBtn:setReferencePoint(display.BottomRightReferencePoint) moveRightBtn.x = display.contentWidth moveRightBtn.y = display.contentHeight function moveRightBtn:touch(event) if event.phase == "began" then motionX = walkingSpeed elseif event.phase == "ended" or event.phase == "cancelled" then motionX = 0 return true end end moveRightBtn:addEventListener("touch", moveRightBtn) --move left local moveLeftBtn = display.newImage("leftArrow.png") moveLeftBtn:setReferencePoint(display.BottomRightReferencePoint) moveLeftBtn.x = display.contentWidth - 100 moveLeftBtn.y = display.contentHeight function moveLeftBtn:touch(event) if event.phase == "began" then --display.getCurrentStage():setFocus(event.target) motionX = -walkingSpeed elseif event.phase == "ended" or event.phase == "cancelled" then motionX = 0 return true end end moveLeftBtn:addEventListener("touch", moveLeftBtn) --motion formula local function movePlayer(event) player.x = player.x + motionX end Runtime:addEventListener("enterFrame", movePlayer) --function that shoots projectiles from the player local function shoot(event) if gameState == 1 then if event.phase == "began" then local bullet = display.newCircle(0, 0, 5) bullet:setFillColor(0,100,200) bullet.x = player.x bullet.y = player.y physics.addBody(bullet) bullet.name = 'bullet' bullet.collision = onCollision bullet:addEventListener("collision", bullet) audio.play(soundBlast) transition.to(bullet, {time=1000, x=display.contentWidth+500}) return true end end return true --to stop conflicting with other taps end --Function to process screen tapping local function onScreenTap(event) if event.phase == "began" shoot(event) return true end end Runtime:addEventListener("touch", onScreenTap) --shoot function called on tap

Hi Tony,

Try un-nesting your “return true” lines from inside the “phase” conditions. Put them at the end of the core function(s), so all phases return true.

Thanks Brent!

I un-nested the return true lines and it worked like a charm. Now I can finally move on, thanks.