Composer scene not removing a scene? Memory issue?

Are there any errors showing up in your console log?

Nope not at all, everything is running as it should. All the other classes remove perfectly, except for the gameOver. It’s just that one class that doesn’t seem to be removing. How I have it set up is when my character runs into an obstacle, it cancels all active timers within the playGame class, and goes to the gameOver scene. When the client goes to that scene, the composer.removeScene(“playGame”) code runes and removes my playGame class which is located in the scene:will. Then in the scene:will part of the playGame class I have composer.removeScene(“gameOver”) which doesn’t execute at all which is confusing because the scene is in memory and should remove.

EDIT: I can add code to show you how it is set up if you’d like.

Can we see the code please?

It sounds like you have a game play scene called playGame.lua, which is the currently loaded scene when the user plays the game. When the character runs into an obstacle, the scene changes to the gameOver.lua scene, which runs composer.removeScene(“playGame”) to remove the playGame.lua scene.

The best way I know of to remove the gameOver scene is to create a blank scene, call it blank.lua. Copy the composer template into this file. Use timers to remove the gameOver scene and transition to whatever scene you want the user to go to. Here’s an example:

local function reloadLvl() composer.removeScene("gameOver") composer.gotoScene("menu") end timer.performWithDelay( 1000, reloadLvl) 

Thats exactly right James! You hit the nail on the head. I’ll give that method a shot. Yeah sure, here is the code I am using:

-- Collision function that goes to gameOver.lua located in the playGame.lua -- Collision for obstacle3 local function onCollision3(event) if event.phase == "began" then local player = event.object1 local op3 = event.object2 if player.type == "player" and op3.type == "op3" then Runtime:removeEventListener("enterFrame", move) Runtime:removeEventListener("enterFrame", move2) Runtime:removeEventListener( "enterFrame", main ) Runtime:removeEventListener("touch", moveAnalog) --physics.stop() transition.cancel("transTag") timer:pauseAllTimers() music.remove() composer.gotoScene("gameOver") end end end Runtime:addEventListener("collision", onCollision3) -- gameOver.lua system.getInfo("model") display.setStatusBar(display.HiddenStatusBar) local composer = require( "composer" ) local scene = composer.newScene() local widget = require("widget") local music = require("bgMusic") local centerY = display.contentCenterY local centerX = display.contentCenterX local screenLeft = display.screenOriginX local screenWidth = display.viewableContentWidth - screenLeft \* 2 local screenRight = screenLeft + screenWidth local screenTop = display.screenOriginY local screenHeight = display.viewableContentHeight - screenTop \* 2 local screenBottom = screenTop + screenHeight local screenTopSB = screenTop + display.topStatusBarContentHeight local screenHeightSB = display.viewableContentHeight - screenTopSB local screenBottomSB = screenTopSB + screenHeightSB local tran, retryBtn, levelBtn, quitBtn, gameOverMenu, gemText, timeText, coinText -- ----------------------------------------------------------------------------------------------------------------- -- All code outside of the listener functions will only be executed ONCE unless "composer.removeScene()" is called. -- ----------------------------------------------------------------------------------------------------------------- -- local forward references should go here -- ------------------------------------------------------------------------------- local function quit(event) local go = event.target.id if go == "quit" then composer.gotoScene("mainMenuBack") music.mmSound() end end local function level(event) local go = event.target.id if go == "levelSel" then composer.gotoScene("levelSelNorm") music.mmSound() end end local function retry(event) local go = event.target.id if go == "retry" then composer.gotoScene("playGame") end end -- "scene:create()" function scene:create( event ) local sceneGroup = self.view -- Initialize the scene here. -- Example: add display objects to "sceneGroup", add touch listeners, etc. end -- "scene:show()" function scene:show( event ) local sceneGroup = self.view local phase = event.phase local group = display.newGroup() group:insert(sceneGroup) if ( phase == "will" ) then -- Called when the scene is still off screen (but is about to come on screen). composer.removeScene("playGame") tran = display.newImageRect("transition.png", 800, 400) tran.x = centerX tran.y = centerY tran.alpha = 0.3 gameOverMenu = display.newImageRect("gameOver/gameOverMenu.png", 528, 295) gameOverMenu.x = 800 gameOverMenu.y = centerY gameOverMenu.alpha = 0 gemText = display.newImageRect("gameOver/gemsText.png", 136, 73) gemText.x = 400 gemText.y = centerY gemText.alpha = 0 timeText = display.newImageRect("gameOver/timeText.png", 132, 72) timeText.x = 400 timeText.y = 120 timeText.alpha = 0 coinText = display.newImageRect("gameOver/coinText.png", 134, 76) coinText.x = 400 coinText.y = 280 coinText.alpha = 0 retryBtn = widget.newButton({width = 200, height = 77, defaultFile = "gameOver/restartBtn.png", id = "retry", onRelease = retry}) retryBtn.x = 600 retryBtn.y = 110 retryBtn.alpha = 0 levelBtn = widget.newButton({width = 201, height = 81, defaultFile = "gameOver/levelSelBtn.png", id = "levelSel", onRelease = level}) levelBtn.x = 600 levelBtn.y = centerY levelBtn.alpha = 0 quitBtn = widget.newButton({width = 201, height = 76, defaultFile = "gameOver/mainMenuBtn.png", id = "quit", onRelease = quit}) quitBtn.x = 600 quitBtn.y = 290 quitBtn.alpha = 0 transition.to(gameOverMenu, {time = 1500, x = 450, alpha = 1}) transition.to(gemText, {delay = 1500, time = 1000, alpha = 1}) transition.to(timeText, {delay = 1500, time = 1000, alpha = 1}) transition.to(coinText, {delay = 1500, time = 1000, alpha = 1}) transition.to(retryBtn, {delay = 1500, time = 1000, alpha = 1}) transition.to(levelBtn, {delay = 1500, time = 1000, alpha = 1}) transition.to(quitBtn, {delay = 1500, time = 1000, alpha = 1}) sceneGroup:insert(tran) sceneGroup:insert(gameOverMenu) sceneGroup:insert(quitBtn) sceneGroup:insert(levelBtn) sceneGroup:insert(retryBtn) sceneGroup:insert(coinText) sceneGroup:insert(timeText) sceneGroup:insert(gemText) elseif ( phase == "did" ) then -- Called when the scene is now on screen. -- Insert code here to make the scene come alive. -- Example: start timers, begin animation, play audio, etc. end end -- "scene:hide()" function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Called when the scene is on screen (but is about to go off screen). -- Insert code here to "pause" the scene. -- Example: stop timers, stop animation, stop audio, etc. elseif ( phase == "did" ) then -- Called immediately after scene goes off screen. end end -- "scene:destroy()" function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's view ("sceneGroup"). -- Insert code here to clean up the scene. -- Example: remove display objects, save state, etc. tran:removeSelf() tran = nil retryBtn:removeSelf() retryBtn = nil levelBtn:removeSelf() levelBtn = nil quitBtn:removeSelf() quitBtn = nil gameOverMenu:removeSelf() gameOverMenu = nil gemText:removeSelf() gemText = nil timeText:removeSelf() timeText = nil coinText:removeSelf() coinText = nil end -- ------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ------------------------------------------------------------------------------- return scene

rburns629, 

One quick note before going any further:

  1. tran:removeSelf()
  2. tran = nil

These are all unnecessary. You have already included these objects in the sceneGroup with sceneGroup:insert(). Composer will takes care of the sceneGroup when the scene is over, including all objects in it. You do not need to destroy them in the scene:destroy function.

Thats what I thought also, but when the scene was not removing I put it in there for testing purposes. Not even the removeSelf() code works.

I would try my earlier suggestion, using  a blank composer scene to move to a new scene and remove the old one. I know it works because I use it and its a legitimate way to clean things up. 

Yea, some code will be helpful.

Rob

Is there a reason you are creating these objects in scene:show() instead of scene:create()?

Is there a reason you are making all these objects global instead of local?

Is there a reason you are creating a display group named group and inserting the scene’s view into that group (lines 95 and 96 above)?

What about the code where you’re trying to remove the gameOver scene?

Just fixed all that Rob. I tried doing everything in the scene:create a while back and it would never work unless I added the sceneGroup to a display.newGroup(). Just moved all the code into the scene:create. The removeScene(“gameOver”) is located in the scene:show of the playGame.lua. Should I put removeScene() outside of the composer functions?

Thanks for your help so far guys. Means a lot.

It sounds to me like perhaps you were moving some storyboard code where we used the name “group” as the scene’s view.  Part of going to composer was to clarify that “sceneGroup” is the scene’s Group.  You should not need to add sceneGroup to some other group and that could potentially create mischief.

You don’t even have to “remove” the scenes for the images from one scene to disappear when you change scenes.  The reason to remove a scene has to do with freeing up memory and causing “scene:create()” to get called again to that things reset back to the original position. 

Perhaps it would be worth while to follow Jame’s suggestion above.  Create a new project.  Use the Composer scene template we provide in the guide to create two scenes.  Create a button in  the scene:create() of the first scene that simply goes to the 2nd scene.  Then in the second scene create a button to go back to the first scene. 

Rob

I have it working now! I appreciate you guys pointing out what you did. It helped a lot.

burns, 

Glad to know you have it working. I wanted to make another suggestion. In your gameOver scene, you are creating separate functions for each of your buttons. I would suggest just one function that loops through conditions. It’s a more concise clean approach. Here’s your code:

local function quit(event) local go = event.target.id if go == "quit" then composer.gotoScene("mainMenuBack") music.mmSound() end end local function level(event) local go = event.target.id if go == "levelSel" then composer.gotoScene("levelSelNorm") music.mmSound() end end local function retry(event) local go = event.target.id if go == "retry" then composer.gotoScene("playGame") end end

Here’s another approach:

local function onButtonRelease(event) local go = event.target.id if go == "quit" then composer.gotoScene("mainMenuBack") music.mmSound() elseif go =="levelSel" then composer.gotoScene("levelSelNorm") music.mmSound() elseif go =="retry" then composer.gotoScene("playGame") end end

The onRelease for each of your buttons will be this function. Your three functions each do the same thing, so it makes sense to combined them into one. It will be easier in the future to make changes to your code. 

That’s a great idea James, thanks. I’ll definitely incorporate that into the code.

Guys, now it is suddenly not working. It was working yesterday and this morning I put the main menu into the scene:create and now the gameOver.lua is not loading at all while mainMenu.lua does. The same thing is happening with my other classes It’s only allowing me to use scene:create with one class, not all. What is going on? is composer bugged or something? I have not changed my gameOver code at all since it was working.

EDIT #1: Just ran some tests. So even when the objects are inserted into the sceneGroup:insert() in scene:create, the objects won’t actually display in the client unless a new display group is associated with sceneGroup. So in scene:will I have local group = display.newGroup() with sceneGroup inside that and it works fine even though all the objects are in scene:create. When I comment out the local group, nothing loads in.

P.S. Rob, I love your github profile picture. Long live the Sith.