onComplete method for composer.showOverlay( )?

I’m looking for a way to determine that my overlay has completed its transition onto the screen.

Basically, I want to pause the game when the overlay finishes transitioning.  Right now I just use a timer.performWithDelay( ) with a delay that matches the transition time but it seems like there could exist a more elegant solution - like an onComplete method or something.

Any thoughts?

Use the show/hide events with will and did phases.

https://docs.coronalabs.com/api/library/composer/index.html

See example: 

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2018/01/overlayOnComplete.zip

https://www.youtube.com/watch?v=6_PfTpgBoTk&feature=youtu.be

BEWARE my code IS NOT standard.  I always split show and hide events into two functions each:

local composer = require( "composer" ) local scene = composer.newScene() function scene:create( event ) local sceneGroup = self.view end function scene:willShow( event ) local sceneGroup = self.view end function scene:didShow( event ) local sceneGroup = self.view end function scene:willHide( event ) local sceneGroup = self.view end function scene:didHide( event ) local sceneGroup = self.view end function scene:destroy( event ) local sceneGroup = self.view end --------------------------------------------------------------------------------- -- Scene Dispatch Events, Etc. - Generally Do Not Touch Below This Line --------------------------------------------------------------------------------- -- This code splits the "show" event into two separate events: willShow and didShow -- for ease of coding above. function scene:show( event ) local sceneGroup = self.view local willDid = event.phase if( willDid == "will" ) then self:willShow( event ) elseif( willDid == "did" ) then self:didShow( event ) end end -- This code splits the "hide" event into two separate events: willHide and didHide -- for ease of coding above. function scene:hide( event ) local sceneGroup = self.view local willDid = event.phase if( willDid == "will" ) then self:willHide( event ) elseif( willDid == "did" ) then self:didHide( event ) end end scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Topical answer… use storyboard.

I use it (well a “customised to what I want” version) in all my games as mainly because it posts back overlay “began” and “ended” events to my main scene.  In an OOP world overlays should never know about the calling scene ( an external dev should be able to code an overlay without ever knowing how it is being used).

My games have a single scene and everything else is an overlay.

Composer is not designed for this schema so I don’t use it.

Thanks Ed and Adrian.  I’ll give it a shot!

@sgs - apparently, storyboard has been deprecated and replaced with composer.  Are you still using storyboard - the API’s still work?

@sporkfin,

I think the code I gave will solve the issue you have, but you can still get the storyboard.lua file here: https://github.com/coronalabs/framework-storyboard-legacy

@roaminggamer,

Your solution worked like a charm!  I was using the standard “will” and “did” phases but could never get them to work properly for this issue.  Your code worked on the first try.  Thanks!

Why can’t you just pass a function to the popup and have it run after the “did”.  Wouldn’t that still maintain your OOP concept?  The popup routine would just run some function if it was there.  function seems like it would be the same as your listener event.  tomato tomato.  

No as it would closely couple the child to the parent. As the child would have to store 2 callbacks (one for began and one for ended).

Maybe I should add that I have modified storyboard some 40% to fit what I need (this was still easier then writing a scene manager from scratch).

Keeping things real simple… assume an overlay existed to prompt the user to a yes/no question.  The popup should NOT be responsible for actioning the yes/no (i.e. doing any work) as that is the responsibility of the parent.  Using this design, the same (dumb) overlay merely prompts the user for input and returns to the parent the users response. This single overlay can then be called under many different scenarios as it is ONLY responsible for handling user input.

Extending this, the overlay I designed to handle user input can be added to any project (without any modification) and this promotes code reuse.

This is one of the main principles of OOP design.

I agree that the popup shouldn’t do the work.  Just send back responses.  But unless it is a dumb yes/no panel you are going to have to pass data to it so it knows what to display.  Passing 2 more fields which doesn’t seem that crazy to me.  It would still be a generic popup function as it would just call the function if present.  In your model what happens.  You set a field somewhere and then call a listener which triggers the parent to process the field?   Where is somewhere?  

The reason all this interests me is I am using showOverlay for the first time and I don’t see an easy way of passing data back to the parent.  I see they have a great way of passing data to the overlay in event.params.   But what is the great way of passing the answers back?   I see some composer global variables.  that seems clunky at best and I see a call back to a function defined to a scene.  Now that is the worst idea I have seen.  Now that ties the overlay to the parent in the worst way.  

My current thought is to pass a function in the params that is the callback onComplete of the overlay.  Then when the overlay is done it would call the function and pass the answers back as function parms.  The callback would resume the game and process the answers to the question which was asked.   Does this make any sense?   I feel like everyone has solved these problems long ago and I am just playing catch up all the time.   But composer should have this stuff as part of it so I don’t have to make up stuff.   :(  

There are plenty of ways of doing things…  In my case I have a single scene with 20 odd overlays.  In my main scene I have scene:overlayBegan() which is automatically called (by storyboard.lua) and that is responsible for doing everything I need when showing an overlay - things like stopping listeners, etc.

When an overlay closes scene:overlayEnded() is again automatically called and handles post overlay processing.  I do have a structure that I fill with data in my overlays and use that to pass data back to my main scene.  

This way I only have 2 functions to handle overlays and it keeps it organised and “simple”.  No passing functions around or having a call back function for each overlay in my main scene.

fwiw, i do same - having access to source makes it no-contest vs composer.  (plus i never needed composer-gui anyway)

@laurasweet8888 we have a great example in the Composer Guide in the Overlay’s section:

https://docs.coronalabs.com/guide/system/composer/index.html#overlays

Basically, you create a function (or functions) in your parent scene and attach it to the scene object:

-- parent scene function scene:myFunction( myParams ) ... end

Then in your overlay:

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 -- Call the "resumeGame()" function in the parent scene parent:myFunction(myParams to pass back) end end

You can have many functions or data values in the parent scene and access/update them from the overlay.

Rob

Then in the overlay scene, 

Bespoke is the only way to get what you want…

For example, in my latest game (almost to be released) I allow the player to tap and drag objects from overlay to the parent - the UI is real slick (even if I do say so myself) - but I have to defer the overlay closing ( and clearing down) by a few seconds to avoid a stall when performing the drag.  The overlay allocates some 30+mb and the GC was a killer!

Here is the result (the farm house is being dragged)

you’ve reinvented storyboard! :smiley:

(my opinion too btw, am on record at the time re converting 4 events to 2-with-2-phases was of ? value)

i’ll say it too, just so you don’t feel guilty.  :D   (well, also because it’s deserved)

@dave,  That looks very nice.  

@SGS,  It seems like you have one function that processes all the data from whichever overlay just ended.  All 20 of them.  I guess that keeps it all in one place.  I assume there is an big if (type of overlay) that does the right thing depending on what just ended.  

@All,   thanks for the thoughts.  In the end, a function needs to run to process returned parms.   Whether that is attached to the scene object,  passed as a parm, or just one function for every overlay.   I was thinking of treating these overlays like the onComplete function of a transition.  Just pass the function to run when the overlay has ended.  But I could see some value in keeping everything in one big function.  Whether or not you reference the function from the scene parent is personal taste I guess.  

L

Use the show/hide events with will and did phases.

https://docs.coronalabs.com/api/library/composer/index.html

See example: 

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2018/01/overlayOnComplete.zip

https://www.youtube.com/watch?v=6_PfTpgBoTk&feature=youtu.be

BEWARE my code IS NOT standard.  I always split show and hide events into two functions each:

local composer = require( "composer" ) local scene = composer.newScene() function scene:create( event ) local sceneGroup = self.view end function scene:willShow( event ) local sceneGroup = self.view end function scene:didShow( event ) local sceneGroup = self.view end function scene:willHide( event ) local sceneGroup = self.view end function scene:didHide( event ) local sceneGroup = self.view end function scene:destroy( event ) local sceneGroup = self.view end --------------------------------------------------------------------------------- -- Scene Dispatch Events, Etc. - Generally Do Not Touch Below This Line --------------------------------------------------------------------------------- -- This code splits the "show" event into two separate events: willShow and didShow -- for ease of coding above. function scene:show( event ) local sceneGroup = self.view local willDid = event.phase if( willDid == "will" ) then self:willShow( event ) elseif( willDid == "did" ) then self:didShow( event ) end end -- This code splits the "hide" event into two separate events: willHide and didHide -- for ease of coding above. function scene:hide( event ) local sceneGroup = self.view local willDid = event.phase if( willDid == "will" ) then self:willHide( event ) elseif( willDid == "did" ) then self:didHide( event ) end end scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Topical answer… use storyboard.

I use it (well a “customised to what I want” version) in all my games as mainly because it posts back overlay “began” and “ended” events to my main scene.  In an OOP world overlays should never know about the calling scene ( an external dev should be able to code an overlay without ever knowing how it is being used).

My games have a single scene and everything else is an overlay.

Composer is not designed for this schema so I don’t use it.