Composer thinks it is on 2 scenes

So right now i am making the gameover part of my game and I came across that the code being printed to the console on my actual game file is being printed while on the gameover screen.

I have no idea how to fix this.

I recreated the problem in a seperate project:

scene1

local function gameLoop() print("On Scene 1") end local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("1",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) Runtime:addEventListener("enterFrame",gameLoop) local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) end circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text)

scene2

local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("2",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) local function gotoTest() composer.gotoScene("scene1") composer.removeScene(self) end local function gameLoop() print("On Scene 2") end Runtime:addEventListener("enterFrame",gameLoop) circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text)

If you paste in the code and run it, you will see that when on scene2, “On Scene1” and “On Scene2” is printed at the same time.

I added in the circle code that when someone clicks on the circle, the scene will remove itself. However, that did not fix the problem

Any idea how I can fix this.

I’d guess it has to do with not removing scene ones’ “enterFrame” event handler (“gameLoop”) before going to scene two.

Event listeners added to Runtime are independent of any scene and the listeners will stay around until they are explicitly removed.

Adding

Runtime:removeEventListener( "enterFrame", gameLoop )

To

gotoTest()

Should fix the problem.  :slight_smile:

-David

So I added that to gotoTest like this:

-------------Scene1-------------- local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop) end ------------Scene2-------------- local function gotoTest() composer.gotoScene("scene1") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop) end

It works when I go from Scene1 to Scene2, however it stops working when I go from Scene2 to Scene1.

What do I do?

Bumping this up.

Need help!

You need to add the event listener in create and remove in destroy.  It is quite simple.  But you will need to give each one a unique name.

Or just have one global game loop and start/stop it when changing scenes.

I tried your first option and it didnt work. I have no idea how to fix this.

So here is my code:

--------------------------------------------------------------------------------- -- -- scene1.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- function scene:create( event ) local sceneGroup = self.view local function gameLoop1() print("On Scene 1") end local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("1",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) Runtime:addEventListener("enterFrame",gameLoop1) local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop1) end circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text) -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) 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 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 -- we obtain the object by id from the scene's object hierarchy -- touch listener for the button -- add the touch event listener to the button end end function scene:hide( event ) 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 end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) Runtime:removeEventListener("enterFrame",gameLoop1) -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

scene2

--------------------------------------------------------------------------------- -- -- scene2.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- function scene:create( event ) local sceneGroup = self.view local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("2",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) local function gameLoop2() print("On Scene 2") end Runtime:addEventListener("enterFrame",gameLoop2) local function gotoTest() composer.gotoScene("scene1") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop2) end circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text) -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) 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 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 -- we obtain the object by id from the scene's object hierarchy -- touch listener for the button -- add the touch event listener to the button end end function scene:hide( event ) 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 end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) Runtime:removeEventListener("enterFrame",gameLoop2) -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Guys, someone help!

You have several things fighting you on this. First, its really important if you’re going to ask for help to format your code well. You have un-indented code making it a challenge for people to understand the flow. It also makes it hard for you to understand the flow. Please read this tutorial:

https://docs.coronalabs.com/tutorial/basics/codeFormatting/index.html

Now on to other issues.

local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop1) end

First, I don’t recommend doing work after going to another scene. In this case, if the removeScene worked (which it probably partially did) the code is destroyed and there is a good chance your removeEventListener might not work.  Secondly you really should not try and remove the scene you are in. The only safe time to do that is in scene:hide() during the “did” phase.  Cancelling runtime listeners is also recommended to be done in scene:hide() during the “will” phase. But it’s perfectly valid to cancel them before you call gotoScene.  I would rewrite that block of code to be:

local function gotoTest() Runtime:removeEventListener("enterFrame",gameLoop1) composer.gotoScene("scene2") end

Then make your scene:hide() : 

function scene:hide( event ) 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 composer.removeScene("thesceenname") end end

You can’t pass self to the removeScene() API, it’s expecting the name of the scene. Since you know the name of your scene, just hard code it.

Finally you have to watch for scope issues. The function gameLoop1 is only known about inside of scene:create().  If you simply move that function outside of scene:create(), then gameLoop1 will be known scene wide and then you could start and stop your enterFrame listener at the right time. If you have any transition time on the scene, lets say you fade the new scene in over 500ms then that means that your enterFrame will be running for 500ms before the user ever sees the screen. It’s always best to defer actions that start activities until the scene is fully on the screen.  Consider this instead of what you have:

local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- -- Put your functions here: local function gameLoop1() print("On Scene 1") end local function gotoTest() composer.gotoScene("scene2") end function scene:create( event ) local sceneGroup = self.view local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) local text = display.newText("1",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) sceneGroup:insert(text) end function scene:show( event ) 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 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 Runtime:addEventListener("enterFrame",gameLoop1) end end function scene:hide( event ) 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.) Runtime:removeEventListener("enterFrame",gameLoop1) elseif phase == "did" then -- Called when the scene is now off screen composer.removeScene("scene1") end end

Rob

Hi Rob,

I tried your code; however, it did not totally solve my issue. Instead of using 2 scenes, I made 3 scenes and it worked perfectly.

I’d guess it has to do with not removing scene ones’ “enterFrame” event handler (“gameLoop”) before going to scene two.

Event listeners added to Runtime are independent of any scene and the listeners will stay around until they are explicitly removed.

Adding

Runtime:removeEventListener( "enterFrame", gameLoop )

To

gotoTest()

Should fix the problem.  :slight_smile:

-David

So I added that to gotoTest like this:

-------------Scene1-------------- local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop) end ------------Scene2-------------- local function gotoTest() composer.gotoScene("scene1") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop) end

It works when I go from Scene1 to Scene2, however it stops working when I go from Scene2 to Scene1.

What do I do?

Bumping this up.

Need help!

You need to add the event listener in create and remove in destroy.  It is quite simple.  But you will need to give each one a unique name.

Or just have one global game loop and start/stop it when changing scenes.

I tried your first option and it didnt work. I have no idea how to fix this.

So here is my code:

--------------------------------------------------------------------------------- -- -- scene1.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- function scene:create( event ) local sceneGroup = self.view local function gameLoop1() print("On Scene 1") end local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("1",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) Runtime:addEventListener("enterFrame",gameLoop1) local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop1) end circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text) -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) 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 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 -- we obtain the object by id from the scene's object hierarchy -- touch listener for the button -- add the touch event listener to the button end end function scene:hide( event ) 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 end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) Runtime:removeEventListener("enterFrame",gameLoop1) -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

scene2

--------------------------------------------------------------------------------- -- -- scene2.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- function scene:create( event ) local sceneGroup = self.view local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) local text = display.newText("2",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) local function gameLoop2() print("On Scene 2") end Runtime:addEventListener("enterFrame",gameLoop2) local function gotoTest() composer.gotoScene("scene1") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop2) end circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) sceneGroup:insert(text) -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) 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 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 -- we obtain the object by id from the scene's object hierarchy -- touch listener for the button -- add the touch event listener to the button end end function scene:hide( event ) 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 end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) Runtime:removeEventListener("enterFrame",gameLoop2) -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

Guys, someone help!

You have several things fighting you on this. First, its really important if you’re going to ask for help to format your code well. You have un-indented code making it a challenge for people to understand the flow. It also makes it hard for you to understand the flow. Please read this tutorial:

https://docs.coronalabs.com/tutorial/basics/codeFormatting/index.html

Now on to other issues.

local function gotoTest() composer.gotoScene("scene2") composer.removeScene(self) Runtime:removeEventListener("enterFrame",gameLoop1) end

First, I don’t recommend doing work after going to another scene. In this case, if the removeScene worked (which it probably partially did) the code is destroyed and there is a good chance your removeEventListener might not work.  Secondly you really should not try and remove the scene you are in. The only safe time to do that is in scene:hide() during the “did” phase.  Cancelling runtime listeners is also recommended to be done in scene:hide() during the “will” phase. But it’s perfectly valid to cancel them before you call gotoScene.  I would rewrite that block of code to be:

local function gotoTest() Runtime:removeEventListener("enterFrame",gameLoop1) composer.gotoScene("scene2") end

Then make your scene:hide() : 

function scene:hide( event ) 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 composer.removeScene("thesceenname") end end

You can’t pass self to the removeScene() API, it’s expecting the name of the scene. Since you know the name of your scene, just hard code it.

Finally you have to watch for scope issues. The function gameLoop1 is only known about inside of scene:create().  If you simply move that function outside of scene:create(), then gameLoop1 will be known scene wide and then you could start and stop your enterFrame listener at the right time. If you have any transition time on the scene, lets say you fade the new scene in over 500ms then that means that your enterFrame will be running for 500ms before the user ever sees the screen. It’s always best to defer actions that start activities until the scene is fully on the screen.  Consider this instead of what you have:

local composer = require( "composer" ) local scene = composer.newScene() ------------------------------- -- Put your functions here: local function gameLoop1() print("On Scene 1") end local function gotoTest() composer.gotoScene("scene2") end function scene:create( event ) local sceneGroup = self.view local circle = display.newCircle(display.contentCenterX,display.contentCenterY,40) circle:addEventListener("tap",gotoTest) sceneGroup:insert(circle) local text = display.newText("1",circle.x,circle.y,native.systemFont,40) text:setFillColor(0) sceneGroup:insert(text) end function scene:show( event ) 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 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 Runtime:addEventListener("enterFrame",gameLoop1) end end function scene:hide( event ) 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.) Runtime:removeEventListener("enterFrame",gameLoop1) elseif phase == "did" then -- Called when the scene is now off screen composer.removeScene("scene1") end end

Rob

Hi Rob,

I tried your code; however, it did not totally solve my issue. Instead of using 2 scenes, I made 3 scenes and it worked perfectly.