Layers and Clicking - Is There an Easier Way?

Considering the following example code:

[lua] – print to console when second image is pressed
function dosomethingelse( event )
print(“clicked2”)
end

– cover screen with blank rectangle and a second image when first image is clicked
function dosomething( event )
print(“clicked1”) – also, print to console when first image is pressed

local rectangle = display.newRect(0,0,display.contentWidth,display.contentHeight)
local img2 = display.newImageRect(“img2.png”,64,64)

rectangle:setFillColor(0)
img2.x = 125
img2.y = 200 – put image 2 in a different spot that doesn’t overlap image 1

img2:addEventListener(“tap”,dosomethingelse)
end

local img1 = display.newImageRect(“img1.png”,64,64)

img.x = 100
img.y = 100

img1:addEventListener(“tap”,dosomething)[/lua]

With the above code, when you click the first image, it’ll show a black overlay with a new image in a different location. Now, if you click the location of the first image, again (even though it can’t be seen), it will still print to the console “clicked1”. Is there an easy way to remove this behaviour without using removeEventListener/addEventListener on every single item covered by the black overlay?

In other words, is there a way for the black overlay to “catch” all the clicks and nullify them if they are for a layer that’s below the overlay?

Another example, for clarity: If you make a game with a small inventory View that pops up, you don’t want to click on any enemies or something that may be hidden by the inventory popup. Is there a way to have clicks only interact with the inventory when clicking within the inventory view, but still able to interact with the HUD or environment when clicking outside the inventory view?

TIA,

Neil [import]uid: 200441 topic_id: 33537 reply_id: 333537[/import]

This still involves adding/removing event listeners, but it will do what you need to and still look pretty clean. Just remember to update the size and location for the area you’re trying to block touches for.

Also remember to insert the touchgrabber into a group above anything else that you want it to block.

[lua]local touchGrabber = display.newRect( 0,0, screenWidth, screenHeight)
touchGrabber.isVisible = false
touchGrabber.isHitTestable = true
local function onGrabberTouch( event ) return true end
local function grabTouches()
touchGrabber:addEventListener( “touch”, onGrabberTouch )
touchGrabber:addEventListener( “tap”, onGrabberTouch )
end
local function stopGrabbingTouches()
touchGrabber:removeEventListener( “touch”, onGrabberTouch )
touchGrabber:removeEventListener( “tap”, onGrabberTouch )
end[/lua] [import]uid: 181948 topic_id: 33537 reply_id: 133273[/import]

I’m not sure if I understand your code correctly, but it sounds like it answers my question perfectly.

If I understand your code correctly, I could insert the touch grabber in the place of the black overlay in my code and then, at some point in my [lua]dosomething[/lua] function, call [lua]stopGrabbingTouches()[/lua] and, in a function that closes the overlay, I would call [lua]grabTouches()[/lua]?

Is that correct?

If it’s not correct, could you please provide a code example of how to use your touch grabber? (if you can use my code to do so, it’d be even easier for me to grasp)

Thanks tons!

Neil [import]uid: 200441 topic_id: 33537 reply_id: 133275[/import]

This code should do what you want

[lua]-- The touch grabber is the same size as img1 and img2 and in the same place
local touchGrabber = display.newRect( 100,100, 64, 64)

local function grabTouches()
touchGrabber:addEventListener( “touch”, onGrabberTouch )
touchGrabber:addEventListener( “tap”, onGrabberTouch )
end
local function stopGrabbingTouches()
touchGrabber:removeEventListener( “touch”, onGrabberTouch )
touchGrabber:removeEventListener( “tap”, onGrabberTouch )
end

– print to console when second image is pressed
function dosomethingelse( event )
print(“clicked2”)
end

– cover screen with blank rectangle and a second image when first image is clicked
function dosomething( event )
print(“clicked1”) – also, print to console when first image is pressed

local rectangle = display.newRect(0,0,display.contentWidth,display.contentHeight)
currentView:insert( rectangle )
local img2 = display.newImageRect(“img2.png”,64,64)
currentView:insert( img2 )

grabTouches()

rectangle:setFillColor(0)
img2.x = 125
img2.y = 200 – put image 2 in a different spot that doesn’t overlap image 1

img2:addEventListener(“tap”,dosomethingelse)
end

– Create a display group to hold everything
local currentView = display.newGroup()
local img1 = display.newImageRect(“img1.png”,64,64)
– Insert the base image into the group
currentView:insert( img1 )
– Insert the touchgrabber after img1 but before img2.
– If you need more control you can shift around the touchgrabber between objects as you need.
currentView:insert( touchgrabber )

img.x = 100
img.y = 100

img1:addEventListener(“tap”,dosomething)[/lua]

Also, you may be able to just do this:
[lua]function dosomethingelse( event )
print(“clicked2”)
return true
end[/lua]. I would try that before you rewrite everything with the touchgrabber :stuck_out_tongue:

-Treb [import]uid: 181948 topic_id: 33537 reply_id: 133277[/import]

Treb, I wasn’t able to factor your code into mine BUT it motivated me to keep experimenting and I found the solution I was looking for, which I was able to circle around and realize I only needed one thing from your code.

[lua]local function onGrabberTouch( event ) return true end
myOverlay:addEventListener(“tap”, onGrabberTouch)[/lua]

Yup, just return true on the deepest layer that you want to receive touches and the obscured portion of every view behind it will have no idea a touch event occured!

Of course, your code also gave me opportunity to learn about [lua]object.isHitTestable[/lua], which would allow me to use an invisible view for blocking touches, without using alpha.

Thanks for your help! [import]uid: 200441 topic_id: 33537 reply_id: 133298[/import]

Awesome, glad you got it working! [import]uid: 181948 topic_id: 33537 reply_id: 133307[/import]

This still involves adding/removing event listeners, but it will do what you need to and still look pretty clean. Just remember to update the size and location for the area you’re trying to block touches for.

Also remember to insert the touchgrabber into a group above anything else that you want it to block.

[lua]local touchGrabber = display.newRect( 0,0, screenWidth, screenHeight)
touchGrabber.isVisible = false
touchGrabber.isHitTestable = true
local function onGrabberTouch( event ) return true end
local function grabTouches()
touchGrabber:addEventListener( “touch”, onGrabberTouch )
touchGrabber:addEventListener( “tap”, onGrabberTouch )
end
local function stopGrabbingTouches()
touchGrabber:removeEventListener( “touch”, onGrabberTouch )
touchGrabber:removeEventListener( “tap”, onGrabberTouch )
end[/lua] [import]uid: 181948 topic_id: 33537 reply_id: 133273[/import]

I’m not sure if I understand your code correctly, but it sounds like it answers my question perfectly.

If I understand your code correctly, I could insert the touch grabber in the place of the black overlay in my code and then, at some point in my [lua]dosomething[/lua] function, call [lua]stopGrabbingTouches()[/lua] and, in a function that closes the overlay, I would call [lua]grabTouches()[/lua]?

Is that correct?

If it’s not correct, could you please provide a code example of how to use your touch grabber? (if you can use my code to do so, it’d be even easier for me to grasp)

Thanks tons!

Neil [import]uid: 200441 topic_id: 33537 reply_id: 133275[/import]

This code should do what you want

[lua]-- The touch grabber is the same size as img1 and img2 and in the same place
local touchGrabber = display.newRect( 100,100, 64, 64)

local function grabTouches()
touchGrabber:addEventListener( “touch”, onGrabberTouch )
touchGrabber:addEventListener( “tap”, onGrabberTouch )
end
local function stopGrabbingTouches()
touchGrabber:removeEventListener( “touch”, onGrabberTouch )
touchGrabber:removeEventListener( “tap”, onGrabberTouch )
end

– print to console when second image is pressed
function dosomethingelse( event )
print(“clicked2”)
end

– cover screen with blank rectangle and a second image when first image is clicked
function dosomething( event )
print(“clicked1”) – also, print to console when first image is pressed

local rectangle = display.newRect(0,0,display.contentWidth,display.contentHeight)
currentView:insert( rectangle )
local img2 = display.newImageRect(“img2.png”,64,64)
currentView:insert( img2 )

grabTouches()

rectangle:setFillColor(0)
img2.x = 125
img2.y = 200 – put image 2 in a different spot that doesn’t overlap image 1

img2:addEventListener(“tap”,dosomethingelse)
end

– Create a display group to hold everything
local currentView = display.newGroup()
local img1 = display.newImageRect(“img1.png”,64,64)
– Insert the base image into the group
currentView:insert( img1 )
– Insert the touchgrabber after img1 but before img2.
– If you need more control you can shift around the touchgrabber between objects as you need.
currentView:insert( touchgrabber )

img.x = 100
img.y = 100

img1:addEventListener(“tap”,dosomething)[/lua]

Also, you may be able to just do this:
[lua]function dosomethingelse( event )
print(“clicked2”)
return true
end[/lua]. I would try that before you rewrite everything with the touchgrabber :stuck_out_tongue:

-Treb [import]uid: 181948 topic_id: 33537 reply_id: 133277[/import]

Treb, I wasn’t able to factor your code into mine BUT it motivated me to keep experimenting and I found the solution I was looking for, which I was able to circle around and realize I only needed one thing from your code.

[lua]local function onGrabberTouch( event ) return true end
myOverlay:addEventListener(“tap”, onGrabberTouch)[/lua]

Yup, just return true on the deepest layer that you want to receive touches and the obscured portion of every view behind it will have no idea a touch event occured!

Of course, your code also gave me opportunity to learn about [lua]object.isHitTestable[/lua], which would allow me to use an invisible view for blocking touches, without using alpha.

Thanks for your help! [import]uid: 200441 topic_id: 33537 reply_id: 133298[/import]

Awesome, glad you got it working! [import]uid: 181948 topic_id: 33537 reply_id: 133307[/import]