Removing/Returning to scenes?

Hello, I am having a problem with scene changing that may be difficult to fully describe, but I will do my best. Currently, what I am trying to do is go from a game scene to a game over scene. On the game over scene is a button that would return the player back to a refreshed game scene.

This is my first project, and I’m sure my code is an absolute nightmare. I’ve been battling with my code for a full three days now and finally have it (at best) in a state where the Game Over scene appears. When I click the button to start over, though, it just transitions to a solid black screen.

From there, I decided my problem might have been that I needed to removeScene() the level scene so it could load from scratch when returned to. However, when I try to call storyboard.removeScene(“level1”) from the enterScreen portion of the game over scene, I get an error that states: “Attempt to perform arithmetic on field ‘y’ (a nil value)” and refers to a line in my level1 scene. I’ve made all of my timers and display objects local variables, and I’ve tried to removeEventListener on all of my Runtime listeners. Still, every time I try to remove the scene it gives me an error. I’ve purchased three Corona SDK books and have scoured the internet trying to learn details about removing/purging/transitioning/returning to scenes, and all I can find is “This is what it’s for”, and “this is sort of how you do it in a simple scenario”.

My questions are:

  1. Does anyone know of a good, thorough resource that explains how storyboard scene changes work, and how to fully clean up a scene?

  2. Does anyone have any idea why I might be seeing the “Attempt to perform arithmetic on field ‘y’ (a nil value)” message referring to my level1 scene when I’m trying to removeScene() from an entirely different scene?

I can add my code here if necessary, but I thought I’d see if I’m missing something blatantly obvious before I spat out 1000 lines of code here.

Thanks for the help :slight_smile:

Also: I’m fully aware that this may not make any sense or the way I’m explaining it is poor, so if there is anything I can do to provide better information please let me know!

When you call removeScene() it causes the scene you are removing to execute it’s destroyScene() event.  I would look in the destroyScene() event of level1.lua and see if you’re doing anything with a .y.

As far as information on what goes on you might find this tutorial somewhat useful:  http://coronalabs.com/blog/2013/08/20/tutorial-reloading-storyboard-scenes/

Thanks for the response, Rob! My destroyScene() event is currently doing nothing but unloading my physics and disposing of my audio. Since I’m still a little bit stumped about scene changes, I currently don’t do a whole lot with my exitScene() and destroyScene(). My workaround was to make everything a local variable/function and pray that changing scenes would clean it up.

It looks like the following line is the culprit. It’s a function set in the enterScene() event of my level1 scene:

local function statusEffects( event )

        if toast.y+35 > fire.y-200 then     <--------It doesn’t like this line? toast and fire are both local display objects

            frameCatcher = frameCatcher+1

            if math.fmod(frameCatcher,10) == 0 and frameCatcher > 0 then

                toastFill = toastFill - 0.1

                toast:setFillColor( toastFill )

            end

        end

        if toast.y+35 < fire.y-200 then

            frameCatcher = 0

        end

    end

Runtime:addEventListener( “enterFrame”, statusEffects )

if I cheat and set up conditionals so it stops running that line manually it just finds another problem somewhere else. I could theoretically try to manually clean up every line it doesn’t like until it’s happy, but I feel like I’m just succumbing to the problem and not learning how it was presented or solved.

As of this moment, it looks like after I transition from my level1 scene to endGame scene, it’s still trying to access my local function statusEffects and do math on toast.y and fire.y (which, given the error, I assume are removed which is why they are nil).

Just for experimentation’s sake I added another Runtime:removeEventListener(“enterFrame”, statusEffects) to a different part of the code, and it seems to have cleared up the first error. Given that, I can reevaluate how I’m removing my event listeners. However, the new problem that appeared is coming from a function that’s accessed via a local timer:

    local function timerFunctions()

        --Warning Message

        if fire.y < display.contentHeight*1.2 then

            if math.fmod(messageHelper,2) == 0 then

                warningMessage.text = “DANGER”

                messageHelper = messageHelper+1

            else

                warningMessage.text = " "

                messageHelper = messageHelper-1

            end

        end

        --Add Raisin1

        if math.fmod(timePlayed,100) == 0 and makeRaisin == 0 and timePlayed > 0 and totalRaisin < 15 then

            local raisin1 = display.newImageRect( “RaisinSmall.png”, 20, 26 )

            raisin1.anchorX = 0.5

            raisin1.anchorY = 0.5

            physics.addBody( raisin1, { density=25, friction=0, bounce=1 } )

            raisin1.x, raisin1.y = display.contentWidth*0.5, -100

            group:insert( raisin1 )

            makeRaisin = makeRaisin+1

            totalRaisin = totalRaisin + 1

        end

        if math.fmod(timePlayed-80,100) == 0 and timePlayed > 0 then

            raisinMessage.text = “Incoming Raisin”

        end

        if math.fmod(timePlayed+10,100) == 0 and timePlayed > 0 then

            raisinMessage.text = " "

            makeRaisin = 0

        end

    end

    local functionTimer = timer.performWithDelay( 400, timerFunctions, 0 )

The eventListener problem I can almost wrap my head around, but how is a local function that’s triggered by a local timer persisting into the next scene?

I apologize for asking such a long and detailed question, but I want to make sure that if I do sort through this there’s a record for others to find since I wasn’t able to find this answer elsewhere.

Also, thank you for pointing me to this video, I am going to delve into it right now! If my answer can be found in this video please don’t trouble yourself with responding, I’ll figure it out from there :slight_smile:

Thanks again!

I’m guessing this is the culprit:

Runtime:addEventListener( “enterFrame”, statusEffects )

If you are adding it in enterScene() you need to remove it in exitScene()
 

Runtime:removeEventListener( “enterFrame”, statusEffects )

because it’s still running and when you remove the scene, the objects that function is trying to access goes away and you get that error.  You are probably saying but I do that.  Well if the statusEffects() function is local to enterScene() then exitScene() can’t know what it is.  Move that function out to the scene’s main chunk (not inside any function) and see if that solves it.

Rob

Thanks Rob! Moving that removeEventListener solved that problem, but I’m still hitting the problem with the local timer persisting. Hopefully I’ll be able to find a solution using the same train of thought you just explained.

I really appreciate the help, thanks again! You rock, Rob :slight_smile:

Just an update:

Despite the fact that my timers were local, I still needed to cancel them manually before the scene changed. Between that and the help you provided, I’m back on track! Also, that video is excellent and very helpful.

Thanks again!

Any thing you create or start in enterScene you need to remove/stop in exitScene except for display objects that have been inserted in the scene group.  So any timers, transitions, Runtime listeners, audio playing, anything that could cause a call back function to execute later (physics collisions, network.requests etc) need stopped in exitScene.  If they were declared local in enterScene, you will have to change them so they are scoped so that exitScene can see them as well.

Rob

Also: I’m fully aware that this may not make any sense or the way I’m explaining it is poor, so if there is anything I can do to provide better information please let me know!

When you call removeScene() it causes the scene you are removing to execute it’s destroyScene() event.  I would look in the destroyScene() event of level1.lua and see if you’re doing anything with a .y.

As far as information on what goes on you might find this tutorial somewhat useful:  http://coronalabs.com/blog/2013/08/20/tutorial-reloading-storyboard-scenes/

Thanks for the response, Rob! My destroyScene() event is currently doing nothing but unloading my physics and disposing of my audio. Since I’m still a little bit stumped about scene changes, I currently don’t do a whole lot with my exitScene() and destroyScene(). My workaround was to make everything a local variable/function and pray that changing scenes would clean it up.

It looks like the following line is the culprit. It’s a function set in the enterScene() event of my level1 scene:

local function statusEffects( event )

        if toast.y+35 > fire.y-200 then     <--------It doesn’t like this line? toast and fire are both local display objects

            frameCatcher = frameCatcher+1

            if math.fmod(frameCatcher,10) == 0 and frameCatcher > 0 then

                toastFill = toastFill - 0.1

                toast:setFillColor( toastFill )

            end

        end

        if toast.y+35 < fire.y-200 then

            frameCatcher = 0

        end

    end

Runtime:addEventListener( “enterFrame”, statusEffects )

if I cheat and set up conditionals so it stops running that line manually it just finds another problem somewhere else. I could theoretically try to manually clean up every line it doesn’t like until it’s happy, but I feel like I’m just succumbing to the problem and not learning how it was presented or solved.

As of this moment, it looks like after I transition from my level1 scene to endGame scene, it’s still trying to access my local function statusEffects and do math on toast.y and fire.y (which, given the error, I assume are removed which is why they are nil).

Just for experimentation’s sake I added another Runtime:removeEventListener(“enterFrame”, statusEffects) to a different part of the code, and it seems to have cleared up the first error. Given that, I can reevaluate how I’m removing my event listeners. However, the new problem that appeared is coming from a function that’s accessed via a local timer:

    local function timerFunctions()

        --Warning Message

        if fire.y < display.contentHeight*1.2 then

            if math.fmod(messageHelper,2) == 0 then

                warningMessage.text = “DANGER”

                messageHelper = messageHelper+1

            else

                warningMessage.text = " "

                messageHelper = messageHelper-1

            end

        end

        --Add Raisin1

        if math.fmod(timePlayed,100) == 0 and makeRaisin == 0 and timePlayed > 0 and totalRaisin < 15 then

            local raisin1 = display.newImageRect( “RaisinSmall.png”, 20, 26 )

            raisin1.anchorX = 0.5

            raisin1.anchorY = 0.5

            physics.addBody( raisin1, { density=25, friction=0, bounce=1 } )

            raisin1.x, raisin1.y = display.contentWidth*0.5, -100

            group:insert( raisin1 )

            makeRaisin = makeRaisin+1

            totalRaisin = totalRaisin + 1

        end

        if math.fmod(timePlayed-80,100) == 0 and timePlayed > 0 then

            raisinMessage.text = “Incoming Raisin”

        end

        if math.fmod(timePlayed+10,100) == 0 and timePlayed > 0 then

            raisinMessage.text = " "

            makeRaisin = 0

        end

    end

    local functionTimer = timer.performWithDelay( 400, timerFunctions, 0 )

The eventListener problem I can almost wrap my head around, but how is a local function that’s triggered by a local timer persisting into the next scene?

I apologize for asking such a long and detailed question, but I want to make sure that if I do sort through this there’s a record for others to find since I wasn’t able to find this answer elsewhere.

Also, thank you for pointing me to this video, I am going to delve into it right now! If my answer can be found in this video please don’t trouble yourself with responding, I’ll figure it out from there :slight_smile:

Thanks again!

I’m guessing this is the culprit:

Runtime:addEventListener( “enterFrame”, statusEffects )

If you are adding it in enterScene() you need to remove it in exitScene()
 

Runtime:removeEventListener( “enterFrame”, statusEffects )

because it’s still running and when you remove the scene, the objects that function is trying to access goes away and you get that error.  You are probably saying but I do that.  Well if the statusEffects() function is local to enterScene() then exitScene() can’t know what it is.  Move that function out to the scene’s main chunk (not inside any function) and see if that solves it.

Rob

Thanks Rob! Moving that removeEventListener solved that problem, but I’m still hitting the problem with the local timer persisting. Hopefully I’ll be able to find a solution using the same train of thought you just explained.

I really appreciate the help, thanks again! You rock, Rob :slight_smile:

Just an update:

Despite the fact that my timers were local, I still needed to cancel them manually before the scene changed. Between that and the help you provided, I’m back on track! Also, that video is excellent and very helpful.

Thanks again!

Any thing you create or start in enterScene you need to remove/stop in exitScene except for display objects that have been inserted in the scene group.  So any timers, transitions, Runtime listeners, audio playing, anything that could cause a call back function to execute later (physics collisions, network.requests etc) need stopped in exitScene.  If they were declared local in enterScene, you will have to change them so they are scoped so that exitScene can see them as well.

Rob