How to reload a scene and proceed like normal?

I have a back button. I have an event listener for when the user taps that button.

When the user taps the button, I need the current scene to be gone like it never happened/existed, and go to a previous scene. Then from there, run through like normal and load everything correctly as if it were the first time running through.

I have researched purge, removal, and gotoScene but they are all confusing me!

Please Explain Clearly. Thanks.

Isiah.

Because of various complexities in how and when storyboard scenes are creating and redrawn, when stuff executes in the module’s main chunk, etc.  I’m not a fan of “reloading” scenes.  I’d much rather go to an intermediate “You lost, try again” level and then remove the scene completely and come back in when you don’t fully understand what all of those issues are.

Just my thoughts/opinion.

Now for your question:

There is a “storyboard.reloadScene()” who’s purpose is to reload a scene.  Of course it won’t re-execute any code run from the main chunk.  it won’t re-execute the createScene() unless you’ve managed to purge the view which has to be done at a very specific point in exitScene().  Your enterScene() has to handle all of the levelRestart logic.

@Rob ok so u suggest not to reload scenes. So whats the best way to cycle through say a collection of 5 scenes.? And I do see the problem with stuff like global variables that change through those scenes. Reloading doesnt change those once they ve been initialized.

.

“I’d much rather go to an intermediate “You lost, try again” level and then remove the scene completely and come back in when you don’t fully understand what all of those issues are.”
What do you mean here? @Rob

Your back button should also be in a scene. 

So when your back button is clicked, you call gotoScene(“YourPreviousSceneName”), then everything in the current scene will be gone and the display will move to the previous scene you specify.

Are you asking a very fundamental question about storyboard & scene or are you having any problem in coding?

Most people want to simply reload a scene and they look for a magical tool to do that.  One might think that simply calling storyboard.gotoScene(“currentscenename”) (where “currentscenename” is the name of your current scene, like “level1”) but that simply doesn’t work.  There is what seems to be the magical answer in storyboard.reloadScene() and it does what it says it does, but it’s not magical. 

You have to know what you’re doing to make it work.  It’s not magic and takes planning and a strong understanding of how Lua modules load and unload, what parts get executed and when and on top of that understanding when storyboard scene events execute.

Because every game/app is different and what you have to do to restart your scene is different it’s very hard, if not impossible to provide an “easy to understand template” or say in a few words how to make this work.  

If you have to go down this path to avoid an intermediate scene then you need to take into consideration.

  1. Code that is executed in the main chunk is run once… ever… unless the module is un-required then re-required.  The storyboard.removeScene() does this, but you really shouldn’t remove the scene that’s on the screen and wait until it’s transitioned off.  If you’re reloading, you’re not transitioning anything off screen, so it’s kind of a bad practice to remove it.  Therefore, code in the main chunk cannot be expected to reset your level.

2.  scene:createScene() is only called if the scene’s view (group) is destroyed.   This happens when the scene is purged after leaving the scene if you have automatic purging on, if the scene is off screen and a low memory event happens or if the scene is off screen and you call storyboard.purgeScene() or storyboard.purgeAll().  The last call won’t purge the active scene.  According to the docs, if you intend to have createScene() called on reload, you must call purgeScene() from the scene:exitScene() or scene:willExitScene() function.  For safety, I would do it as the very last thing in exitScene.

3.  The only  guarenteed functions to execute on a reload is scene:exitScene() and then scene:enterScene() (well the willExitScene and willEnterScene get called).  Therefore you have to:

a. in your main chunk, define the variables that need to survive the reload but do not depend on their initialization as they will keep their last values during the reload.

b. create your visual assets in scene:createScene() for their initial locations.

c. in willEnterScene() initialize any variables that need to be reset on a reload or initial load.  Position any graphical elements that could have moved that need to go back to their starting position.

d. in enterScene() start up any timers, transitions, Runtime listeners, physics, audio, etc.

e. in exitScene() undo anything you did in enterScene and the last thing call storyboard.purgeScene() if you want createScene() to re-execute.

Then if you’re lucky you can use storyboard.reloadScene() to actually reload the scene.  If you pass any parameters to the scene on your initial gotoScene(), those are not passed back in.  You have to save/set those values in your willEnterScene initialization code.

Ok this helps tremendously. @Rob So if I do it your way, what if I use an intermediate scene, how does that work? Like say from scene 5, someone taps the back button, and they need to go back to scene 1 and have the code run through again minus some variables resetting. Whats the intermediate scene supposed to have?

The easy way:

main.lua (not a real scene but starts the whole process) --> menu.lua  -->  level1.lua  --> tryagain.lua --> level1.lua

Now in tryagain.lua display a message for a few seconds and then while that’s displaying call storyboard.removeScene(“level1”); storyboard.gotoScene(“level1”)

to go back.  The scene is completely dumped and reloaded and you don’t have to futz with making sure that you reset everything correctly.  The level actually restarts from scratch.

@Rob thank you very much. It’s working great! No issues! I really appreciate your in-depth explanations. Sometimes the docs can get a little bland and when I need more detail, or maybe something in “baby-talk” to where I can understand it, you never fail!! Thanks again.

i do something similar for a “redo” button, in rough pseudocode…

– PlayScene.lua

local function onRedoPress(e)

  storyboard.gotoScene(“RedoScene”)

  – you don’t want to just call storyboard.gotoScene(“PlayScene”) here

  – as your exit/enter’s can get mixed up if you try coming and going to/from same scene at once

end

– RedoScene.lua

– essentially a do-nothing scene

– as soon as we get here we head right back to PlayScene

– but in the mean time PlayScene has had a chance to fully exit

function scene:onEnterScene()

  – you can safely purge/remove here (if you need to) prior to reentering PlayScene…

  – for my use (redo) i just wanted to launch it up again fresh from the start…

  storyboard.gotoScene(“PlayScene”)

end

Because of various complexities in how and when storyboard scenes are creating and redrawn, when stuff executes in the module’s main chunk, etc.  I’m not a fan of “reloading” scenes.  I’d much rather go to an intermediate “You lost, try again” level and then remove the scene completely and come back in when you don’t fully understand what all of those issues are.

Just my thoughts/opinion.

Now for your question:

There is a “storyboard.reloadScene()” who’s purpose is to reload a scene.  Of course it won’t re-execute any code run from the main chunk.  it won’t re-execute the createScene() unless you’ve managed to purge the view which has to be done at a very specific point in exitScene().  Your enterScene() has to handle all of the levelRestart logic.

@Rob ok so u suggest not to reload scenes. So whats the best way to cycle through say a collection of 5 scenes.? And I do see the problem with stuff like global variables that change through those scenes. Reloading doesnt change those once they ve been initialized.

.

“I’d much rather go to an intermediate “You lost, try again” level and then remove the scene completely and come back in when you don’t fully understand what all of those issues are.”
What do you mean here? @Rob

Your back button should also be in a scene. 

So when your back button is clicked, you call gotoScene(“YourPreviousSceneName”), then everything in the current scene will be gone and the display will move to the previous scene you specify.

Are you asking a very fundamental question about storyboard & scene or are you having any problem in coding?

Most people want to simply reload a scene and they look for a magical tool to do that.  One might think that simply calling storyboard.gotoScene(“currentscenename”) (where “currentscenename” is the name of your current scene, like “level1”) but that simply doesn’t work.  There is what seems to be the magical answer in storyboard.reloadScene() and it does what it says it does, but it’s not magical. 

You have to know what you’re doing to make it work.  It’s not magic and takes planning and a strong understanding of how Lua modules load and unload, what parts get executed and when and on top of that understanding when storyboard scene events execute.

Because every game/app is different and what you have to do to restart your scene is different it’s very hard, if not impossible to provide an “easy to understand template” or say in a few words how to make this work.  

If you have to go down this path to avoid an intermediate scene then you need to take into consideration.

  1. Code that is executed in the main chunk is run once… ever… unless the module is un-required then re-required.  The storyboard.removeScene() does this, but you really shouldn’t remove the scene that’s on the screen and wait until it’s transitioned off.  If you’re reloading, you’re not transitioning anything off screen, so it’s kind of a bad practice to remove it.  Therefore, code in the main chunk cannot be expected to reset your level.

2.  scene:createScene() is only called if the scene’s view (group) is destroyed.   This happens when the scene is purged after leaving the scene if you have automatic purging on, if the scene is off screen and a low memory event happens or if the scene is off screen and you call storyboard.purgeScene() or storyboard.purgeAll().  The last call won’t purge the active scene.  According to the docs, if you intend to have createScene() called on reload, you must call purgeScene() from the scene:exitScene() or scene:willExitScene() function.  For safety, I would do it as the very last thing in exitScene.

3.  The only  guarenteed functions to execute on a reload is scene:exitScene() and then scene:enterScene() (well the willExitScene and willEnterScene get called).  Therefore you have to:

a. in your main chunk, define the variables that need to survive the reload but do not depend on their initialization as they will keep their last values during the reload.

b. create your visual assets in scene:createScene() for their initial locations.

c. in willEnterScene() initialize any variables that need to be reset on a reload or initial load.  Position any graphical elements that could have moved that need to go back to their starting position.

d. in enterScene() start up any timers, transitions, Runtime listeners, physics, audio, etc.

e. in exitScene() undo anything you did in enterScene and the last thing call storyboard.purgeScene() if you want createScene() to re-execute.

Then if you’re lucky you can use storyboard.reloadScene() to actually reload the scene.  If you pass any parameters to the scene on your initial gotoScene(), those are not passed back in.  You have to save/set those values in your willEnterScene initialization code.

Ok this helps tremendously. @Rob So if I do it your way, what if I use an intermediate scene, how does that work? Like say from scene 5, someone taps the back button, and they need to go back to scene 1 and have the code run through again minus some variables resetting. Whats the intermediate scene supposed to have?

The easy way:

main.lua (not a real scene but starts the whole process) --> menu.lua  -->  level1.lua  --> tryagain.lua --> level1.lua

Now in tryagain.lua display a message for a few seconds and then while that’s displaying call storyboard.removeScene(“level1”); storyboard.gotoScene(“level1”)

to go back.  The scene is completely dumped and reloaded and you don’t have to futz with making sure that you reset everything correctly.  The level actually restarts from scratch.

@Rob thank you very much. It’s working great! No issues! I really appreciate your in-depth explanations. Sometimes the docs can get a little bland and when I need more detail, or maybe something in “baby-talk” to where I can understand it, you never fail!! Thanks again.