Overlay Modal Preventing Parent Elements From Being Clicked Even After Overlay Is Closed

Hi All,

Before I try knocking together a simpler test case, does anyone have any ideas as to what may cause the following issue.

I have a scene with numerous clickable/touchable elements/buttons, one of which opens an overlay using “composer.showOverlay”.  

The overlay itself works as expected, but on leaving the overlay which calls “composer.hideOverlay” and subsequently “parent:resumeGame()” in “scene:hide” none of the elements on my parent scene can be clicked anymore.

The code within the resumeGame() function runs as expected, it’s just the click events seem to no longer work.

In a previous forum response from Rob he stated that “The model overlay scene already puts a transparent full screen rectangle on the overlay’s background that intercepts both touch and tap handlers for you.”.  Could it be that this object is still in existence even though I have left/closed the overlay?

Is there a way to identify this transparent rectangle or check if the touch handlers are still being intercepted?

I have other overlays in the application which work fine, and this particular issue wasn’t present until I updated my SDK to Version: 3.0.0 Build: 2017.3184 the other night.  However my previous version was over 2 years old, so I can’t really identify a particular build where this issue started occurring.

Simon

On 8/18/2017, we changed how model overlays were working. Prior to this, when a scene was transitioning, clicks would go through to the background. The change doesn’t remove the model overlay until the scene is hidden. However, there are no reports of this change being broken, but it’s a behavior difference that you would see in the current public build. The touch blocker is removed just before the overlay scene get’s it’s “hide” event with a “did” phase.

 

Rob

Hi Rob,

Interesting.  Is there a way to check the touch blocker has been removed successfully?  I think I am starting to see a pattern in my application.

Most overlays work fine for me, but this issue only seems to appear on a select few, and these few do have things in common.

  1. The user accesses a confirmation overlay from the parent screen.

  2. On clicking an “OK” button, the overlay is hidden and control passed back to the parent, which then makes a synchronous web service request before automatically showing a second overlay containing details from the request.

  3. It is when this second overlay is closed that the problem occurs.

I am only showing one overlay at a time, BUT these are two different overlays.  I can’t imagine the web service would interfere with the UI side of things, so I suspect its the spawning of the second overlay which is causing the issue.  In which case it might be easier for me to try and isolate within a test case.

In the meantime if the above method raises any alarm bells, or if you know how I can check whether the touch blocker still exists, then please let me know.

Simon

A test case would be quite helpful.

Rob

Right then,

I’ve tried to simulate this as simply as possible.  It prints to the console each thing its trying to do.  Assume you don’t need my build settings and config.

So I have 4 lua files, main.lua (which runs my main parent scene), test.lua (The parent scene with 2 buttons - all the second one does is output text to the console for demonstrating the issue), overlay1.lua and overlay2.lua (each of which have a back button and pass control back to the parent.

When you run the program initially you can click the second button as many times as you like and it works.

If you click the first button the first overlay opens (which prevents the buttons on the parent from being clicked, as expected).

Closing overlay 1 runs some code on the parent (scene:resumeGame1()) and then runs overlay 2.  Closing overlay 2 again returns control to the parent (scene:resumeGame2()), but from here on in no buttons can be clicked.

MAIN.LUA

--------------------------------------------------------------------------------- -- -- main.lua - The main startup shell -- --------------------------------------------------------------------------------- -- Load external Library's local composer = require("composer") --------------------------------------------------------------------------------- -- -- Main Scene Control -- --------------------------------------------------------------------------------- -- Start Test Screen composer.gotoScene( "test" ) 

TEST.LUA

--------------------------------------------------------------------------------- -- -- Test.lua - The Main Parent Screen -- --------------------------------------------------------------------------------- -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() local popupTransitionOptions = {isModal = true, effect = "fade", time = 300} --------------------------------------------------------------------------------- -- -- Scene Controls/Setup -- --------------------------------------------------------------------------------- -- Called when the scene's view does not exist -- INSERT code here to initialize the scene e.g. add display objects to 'sceneGroup', add touch listeners, etc function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=button1Clicked, onRelease=button1Selected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 335 sceneGroup:insert(button1) button2 = widget.newButton({onPress=button2Clicked, onRelease=button2Selected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button2.x = display.contentCenterX + 84 button2.y = display.contentCenterY + 335 sceneGroup:insert(button2) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end ---------- function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive e.g. start timers, begin animation, play audio, etc composer.removeHidden() end return true end ---------- function scene:hide( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- INSERT code here to pause the scene e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end return true end ---------- function scene:destroy( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) -- INSERT code here to cleanup the scene e.g. remove display objects, remove touch listeners, save state, etc return true end -- Custom function for resuming the game from overlay 1 function scene:resumeGame1() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 1") print("RUNNING SECOND OVERLAY") -- Show the overlay composer.showOverlay( "overlay2", popupTransitionOptions ) return true end -- Custom function for resuming the game from overlay 2 function scene:resumeGame2() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 2") return true end -------------- -- Button 1 -------------- function button1Clicked( event ) print("BUTTON 1 CLICKED") return true end function button1Selected( event ) print("BUTTON 1 SELECTED") -- Show the overlay composer.showOverlay( "overlay1", popupTransitionOptions ) return true end -------------- -- Button 2 -------------- function button2Clicked( event ) print("BUTTON 2 CLICKED") return true end function button2Selected( event ) print("BUTTON 2 SELECTED") return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

OVERLAY1.LUA

------------------------------------------------------------------------------ -- -- Overlay1.lua - First Overlay -- ------------------------------------------------------------------------------ -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=okButtonClicked, onRelease=okButtonSelected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 100 sceneGroup:insert(button1) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase local parent = event.parent --reference to the parent scene object if ( phase == "will" ) then parent:resumeGame1() -- returning original passed in params end end --------------------------------------------------------------------------------- -- -- Event Handling -- --------------------------------------------------------------------------------- -------------- -- OK Button -------------- function okButtonClicked( event ) print("OK CLICKED") return true end function okButtonSelected( event ) print("HIDING OVERLAY 1") composer.hideOverlay( "fade", 100 ) return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

OVERLAY2.LUA

------------------------------------------------------------------------------ -- -- Overlay2.lua - Second Overlay -- ------------------------------------------------------------------------------ -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=okButtonClicked, onRelease=okButtonSelected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 100 sceneGroup:insert(button1) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase local parent = event.parent --reference to the parent scene object if ( phase == "will" ) then parent:resumeGame2() -- returning original passed in params end end --------------------------------------------------------------------------------- -- -- Event Handling -- --------------------------------------------------------------------------------- -------------- -- OK Button -------------- function okButtonClicked( event ) print("OK CLICKED") return true end function okButtonSelected( event ) print("HIDING OVERLAY 2") composer.hideOverlay( "fade", 100 ) return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Make a project we can download. That would be a lot nicer.

  1. Make a fully functional example project that demonstrates the issue.

  2. Zip it up.

  3. Click ‘More Reply Options’ Button below.

  4. Do this:  attaching_files.jpg
     

Ahh Brilliant, sure thing, I was wondering how to upload files. 

I have (hopefully) attached the zip file now.  And just to recap:

There are 4 lua files, main.lua (which runs my main parent scene), test.lua (The parent scene with 2 buttons - all the second one does is output text to the console for demonstrating the issue), overlay1.lua and overlay2.lua (each of which have a back button and pass control back to the parent.

 

When you run the program initially you can click the second button as many times as you like and it works.

 

If you click the first button the first overlay opens (which prevents the buttons on the parent from being clicked, as expected).

 

Closing overlay 1 runs some code on the parent (scene:resumeGame1()) and then runs overlay 2.  Closing overlay 2 again returns control to the parent (scene:resumeGame2()), but from here on in no buttons can be clicked.

and this is why I use my bastardised version of storyboard…

I get to customise behaviour to what I want

So basically I’ve found the issue and I’ve come up with a workaround. Composer allows one overlay **at a time**. That last part is the key. What defines “at a time”. You’re using transitions on hiding and showing the overlays, This adds to the time the overlay lives. The overlay touch blocker exists in the composer object, not the scene object. This feels like a race condition, but I don’t see a clear way to solve it because the overlay blocker needs to exist before the scene shows to prevent touches during the transition.  The reason this now impacts you is that previously we were removing the overlay earlier in the process (thus creating the bug allowing touches to make it to the background).

We can’t really have this both ways. Either we have the overlay block the scene for its life or we have it block when it’s fully on screen. The workaround, which I would suggest you consider is to use a timer.

function scene:resumeGame1() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 1") print("RUNNING SECOND OVERLAY") -- Show the overlay timer.performWithDelay(400, function() composer.showOverlay( "overlay2", popupTransitionOptions ) end) return true end

The duration of the timer seems to be related to the transition time. I believe your sample is using 300ms.

Rob

I gave up with Composer because of this. My games only use overlays and this was a real issue.

Basically you are loading a new overlay before the old one has been completely dealt with and the touch blocker gets orphaned.

An easy win would be to just kill the overlay instantly - i.e. remove the transition.

or, if require transition, at least defer until hide-did instead of hide-will

Brilliant, thanks for the suggestions folks.  Looks like I’ve got some refactoring to do :slight_smile:

On 8/18/2017, we changed how model overlays were working. Prior to this, when a scene was transitioning, clicks would go through to the background. The change doesn’t remove the model overlay until the scene is hidden. However, there are no reports of this change being broken, but it’s a behavior difference that you would see in the current public build. The touch blocker is removed just before the overlay scene get’s it’s “hide” event with a “did” phase.

 

Rob

Hi Rob,

Interesting.  Is there a way to check the touch blocker has been removed successfully?  I think I am starting to see a pattern in my application.

Most overlays work fine for me, but this issue only seems to appear on a select few, and these few do have things in common.

  1. The user accesses a confirmation overlay from the parent screen.

  2. On clicking an “OK” button, the overlay is hidden and control passed back to the parent, which then makes a synchronous web service request before automatically showing a second overlay containing details from the request.

  3. It is when this second overlay is closed that the problem occurs.

I am only showing one overlay at a time, BUT these are two different overlays.  I can’t imagine the web service would interfere with the UI side of things, so I suspect its the spawning of the second overlay which is causing the issue.  In which case it might be easier for me to try and isolate within a test case.

In the meantime if the above method raises any alarm bells, or if you know how I can check whether the touch blocker still exists, then please let me know.

Simon

A test case would be quite helpful.

Rob

Right then,

I’ve tried to simulate this as simply as possible.  It prints to the console each thing its trying to do.  Assume you don’t need my build settings and config.

So I have 4 lua files, main.lua (which runs my main parent scene), test.lua (The parent scene with 2 buttons - all the second one does is output text to the console for demonstrating the issue), overlay1.lua and overlay2.lua (each of which have a back button and pass control back to the parent.

When you run the program initially you can click the second button as many times as you like and it works.

If you click the first button the first overlay opens (which prevents the buttons on the parent from being clicked, as expected).

Closing overlay 1 runs some code on the parent (scene:resumeGame1()) and then runs overlay 2.  Closing overlay 2 again returns control to the parent (scene:resumeGame2()), but from here on in no buttons can be clicked.

MAIN.LUA

--------------------------------------------------------------------------------- -- -- main.lua - The main startup shell -- --------------------------------------------------------------------------------- -- Load external Library's local composer = require("composer") --------------------------------------------------------------------------------- -- -- Main Scene Control -- --------------------------------------------------------------------------------- -- Start Test Screen composer.gotoScene( "test" ) 

TEST.LUA

--------------------------------------------------------------------------------- -- -- Test.lua - The Main Parent Screen -- --------------------------------------------------------------------------------- -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() local popupTransitionOptions = {isModal = true, effect = "fade", time = 300} --------------------------------------------------------------------------------- -- -- Scene Controls/Setup -- --------------------------------------------------------------------------------- -- Called when the scene's view does not exist -- INSERT code here to initialize the scene e.g. add display objects to 'sceneGroup', add touch listeners, etc function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=button1Clicked, onRelease=button1Selected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 335 sceneGroup:insert(button1) button2 = widget.newButton({onPress=button2Clicked, onRelease=button2Selected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button2.x = display.contentCenterX + 84 button2.y = display.contentCenterY + 335 sceneGroup:insert(button2) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end ---------- function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive e.g. start timers, begin animation, play audio, etc composer.removeHidden() end return true end ---------- function scene:hide( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- INSERT code here to pause the scene e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end return true end ---------- function scene:destroy( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) -- INSERT code here to cleanup the scene e.g. remove display objects, remove touch listeners, save state, etc return true end -- Custom function for resuming the game from overlay 1 function scene:resumeGame1() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 1") print("RUNNING SECOND OVERLAY") -- Show the overlay composer.showOverlay( "overlay2", popupTransitionOptions ) return true end -- Custom function for resuming the game from overlay 2 function scene:resumeGame2() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 2") return true end -------------- -- Button 1 -------------- function button1Clicked( event ) print("BUTTON 1 CLICKED") return true end function button1Selected( event ) print("BUTTON 1 SELECTED") -- Show the overlay composer.showOverlay( "overlay1", popupTransitionOptions ) return true end -------------- -- Button 2 -------------- function button2Clicked( event ) print("BUTTON 2 CLICKED") return true end function button2Selected( event ) print("BUTTON 2 SELECTED") return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

OVERLAY1.LUA

------------------------------------------------------------------------------ -- -- Overlay1.lua - First Overlay -- ------------------------------------------------------------------------------ -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=okButtonClicked, onRelease=okButtonSelected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 100 sceneGroup:insert(button1) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase local parent = event.parent --reference to the parent scene object if ( phase == "will" ) then parent:resumeGame1() -- returning original passed in params end end --------------------------------------------------------------------------------- -- -- Event Handling -- --------------------------------------------------------------------------------- -------------- -- OK Button -------------- function okButtonClicked( event ) print("OK CLICKED") return true end function okButtonSelected( event ) print("HIDING OVERLAY 1") composer.hideOverlay( "fade", 100 ) return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

OVERLAY2.LUA

------------------------------------------------------------------------------ -- -- Overlay2.lua - Second Overlay -- ------------------------------------------------------------------------------ -- Load external Library's local composer = require("composer") local widget = require("widget") -- Load scene with same root filename as this file local scene = composer.newScene() function scene:create( event ) -- Required for composer to manage the scene local sceneGroup = self.view -- default to TopLeft anchor point for new objects display.setDefault( "anchorX", 0.0 ) display.setDefault( "anchorY", 0.0 ) button1 = widget.newButton({onPress=okButtonClicked, onRelease=okButtonSelected, font="Arial", isEnabled=true, defaultFile="BackButton.png", overFile="BackButtonHover.png"}) button1.x = display.contentCenterX - 84 button1.y = display.contentCenterY + 100 sceneGroup:insert(button1) -- restore anchor points for new objects to center anchor point display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) return true end function scene:show( event ) -- Required for composer to manage the scene local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen -- Set screen title, buttons etc elseif phase == "did" then -- Called when the scene is now on screen -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase local parent = event.parent --reference to the parent scene object if ( phase == "will" ) then parent:resumeGame2() -- returning original passed in params end end --------------------------------------------------------------------------------- -- -- Event Handling -- --------------------------------------------------------------------------------- -------------- -- OK Button -------------- function okButtonClicked( event ) print("OK CLICKED") return true end function okButtonSelected( event ) print("HIDING OVERLAY 2") composer.hideOverlay( "fade", 100 ) return true end --------------------------------------------------------------------------------- -- -- Listener Setup -- --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Make a project we can download. That would be a lot nicer.

  1. Make a fully functional example project that demonstrates the issue.

  2. Zip it up.

  3. Click ‘More Reply Options’ Button below.

  4. Do this:  attaching_files.jpg
     

Ahh Brilliant, sure thing, I was wondering how to upload files. 

I have (hopefully) attached the zip file now.  And just to recap:

There are 4 lua files, main.lua (which runs my main parent scene), test.lua (The parent scene with 2 buttons - all the second one does is output text to the console for demonstrating the issue), overlay1.lua and overlay2.lua (each of which have a back button and pass control back to the parent.

 

When you run the program initially you can click the second button as many times as you like and it works.

 

If you click the first button the first overlay opens (which prevents the buttons on the parent from being clicked, as expected).

 

Closing overlay 1 runs some code on the parent (scene:resumeGame1()) and then runs overlay 2.  Closing overlay 2 again returns control to the parent (scene:resumeGame2()), but from here on in no buttons can be clicked.

and this is why I use my bastardised version of storyboard…

I get to customise behaviour to what I want

So basically I’ve found the issue and I’ve come up with a workaround. Composer allows one overlay **at a time**. That last part is the key. What defines “at a time”. You’re using transitions on hiding and showing the overlays, This adds to the time the overlay lives. The overlay touch blocker exists in the composer object, not the scene object. This feels like a race condition, but I don’t see a clear way to solve it because the overlay blocker needs to exist before the scene shows to prevent touches during the transition.  The reason this now impacts you is that previously we were removing the overlay earlier in the process (thus creating the bug allowing touches to make it to the background).

We can’t really have this both ways. Either we have the overlay block the scene for its life or we have it block when it’s fully on screen. The workaround, which I would suggest you consider is to use a timer.

function scene:resumeGame1() -- Do Nothing, resume game print("CONTOL RETURNED TO PARENT FROM OVERLAY 1") print("RUNNING SECOND OVERLAY") -- Show the overlay timer.performWithDelay(400, function() composer.showOverlay( "overlay2", popupTransitionOptions ) end) return true end

The duration of the timer seems to be related to the transition time. I believe your sample is using 300ms.

Rob