Having problem moving from one scene to the other using composer

So I have two scenes. They contain exactly the same code ( for testing purposes only). When i run the first scene it works as expected but when I move from “level1” to “level2” I get an error in “level2”.  “Attempt to call method ‘setLinearVelocity’ (a nil value)” even though they contain the same code. The code below does not contain any images so you can copy and paste it and it should work fine. I think i might be doing something wrong in the “show” and “hide” scene event. Please help me.

local physics = require "physics" local composer = require( "composer" ) local scene = composer.newScene() local player local ground local onAir local obstacle local obstacle2 local obstacle3 local playerStartX local playerStartY local playerNextX local playerNextY local star local starEnd -- "scene:create()" function scene:create( event ) local sceneGroup = self.view physics.start() physics.setGravity( 0, 100 ) onAir = false playerStartX = 20 playerStartY = display.contentHeight\*0.5-20 playerNextX = 20 playerNextY = display.contentHeight - 18 player = display.newRect( playerStartX, playerStartY, 20,20 ) player.speed = 3 player.name = "player" player:setFillColor( 1 ) player.isFixedRotation = true --To stop it rotating when jumping etc player.isSleepingAllowed = false --To force it to update and fall off playforms correctly. sceneGroup:insert( player ) ground = display.newRect( 0, display.contentHeight\*0.5-5, display.contentWidth, 5 ) ground.anchorX = 0 ground.anchorY = 0 ground.name = "ground" ground.strokeWidth = 3 ground:setFillColor( 0.5 ) ground:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground ) ground2 = display.newRect( 0, display.contentHeight-5, display.contentWidth, 5 ) ground2.anchorX = 0 ground2.anchorY = 0 ground2.name = "ground" ground2.strokeWidth = 3 ground2:setFillColor( 0.5 ) ground2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground2 ) obstacle = display.newRect( display.contentWidth\*0.5, display.contentHeight\*0.5-46, 20, 40 ) obstacle.anchorX = 0 obstacle.anchorY = 0 obstacle.name = "obstacle" obstacle.strokeWidth = 3 obstacle:setFillColor( 0.5 ) obstacle:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle ) obstacle2 = display.newRect( display.contentWidth\*0.5 - 100, display.contentHeight-46, 20, 40 ) obstacle2.anchorX = 0 obstacle2.anchorY = 0 obstacle2.name = "obstacle" obstacle2.strokeWidth = 3 obstacle2:setFillColor( 0.5 ) obstacle2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle2 ) obstacle3 = display.newRect( display.contentWidth\*0.5 + 60, display.contentHeight-46, 20, 40 ) obstacle3.anchorX = 0 obstacle3.anchorY = 0 obstacle3.name = "obstacle" obstacle3.strokeWidth = 3 obstacle3:setFillColor( 0.5 ) obstacle3:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle3 ) star = display.newRect( display.contentWidth - 10,display.contentHeight\*0.5 - 20, 20, 20 ) star.name = "star" sceneGroup:insert( star ) starEnd = display.newRect( display.contentWidth - 10,display.contentHeight - 20, 20, 20 ) starEnd.name = "starEnd" sceneGroup:insert( starEnd ) physics.addBody( player, "dynamic", { density=1, friction=0.3} ) physics.addBody( ground, "static", { friction=0.5, bounce=0 } ) physics.addBody( ground2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle3, "static", { friction=0.5, bounce=0 } ) physics.addBody( star, "static" ) physics.addBody( starEnd, "static" ) end-- end of the scene --make the player jump when touching the screen function screenTouch( event ) if event.phase == "began" then if onAir == false then player:setLinearVelocity(0,-880) onAir = true end end end function walls( event ) if player.x \< 10 then player.x = 10 elseif player.x \> display.contentWidth-10 then player.x = display.contentWidth-10 end if player.y \< 10 then player.y = 10 elseif player.y \> display.contentHeight then player.y = display.contentHeight end end function onCollision(event) if event.phase == "began" then local name1 = event.object1.name local name2 = event.object2.name if name1 == "player" or name2 == "player" then --Hit the floor, reset vars if name1 == "ground" or name2 == "ground" then onAir = false elseif name1 == "obstacle" or name2 == "obstacle" then timer.performWithDelay(1, moveBackToCheckPoint) elseif name1 == "star" or name2 == "star" then --remove the star if name1 == "star" then --remove the star display.remove(event.object1); event.object1 = nil; else display.remove(event.object2); event.object2 = nil; end timer.performWithDelay(1, goToNextPosition) elseif name1 == "starEnd" or name2 == "starEnd" then goToNextLevel() end end end end function moveBall( event ) player.x = player.x + player.speed end function moveBackToCheckPoint( event ) player.x = playerStartX player.y = playerStartY end function goToNextPosition(event) playerStartX = playerNextX playerStartY = playerNextY player.x = playerNextX player.y = playerNextY end function goToNextLevel( event ) composer.removeScene( "level1") composer.gotoScene( "level2" ) end -- "scene:show()" function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then Runtime:addEventListener( "touch", screenTouch ) Runtime:addEventListener("collision",onCollision) Runtime:addEventListener("enterFrame", moveBall) Runtime:addEventListener("enterFrame", walls) -- 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 -- pauseBtn:removeEventListener( "tap", pauseGame ) -- Called immediately after scene goes off screen. end end -- "scene:destroy()" function scene:destroy( event ) local sceneGroup = self.view Runtime:removeEventListener( "touch", screenTouch ) Runtime:removeEventListener("collision",onCollision) Runtime:removeEventListener("enterFrame", moveBall) Runtime:removeEventListener("enterFrame", walls) -- 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. end -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene

LIkely its a problem due to when you do things.  If you do something in scene:show() you need to undo it in scene:hide().  However you are deferring removing your runtime listeners and collision listeners until the scene:destroy() event which can come after the scene is off the screen.  Also, I don’t like trying to remove the scene that’s currently on the screen before you goto another scene.  I would take your code out of destroy, put it in hide.  Then leave that scene be and remove the scene you are getting ready to go to.

In other words:

composer.removeScene(“level1”)

composer.gotoScene(“level1”)

composer.removeScene(“level2”)

composer.gotoScene(“level2”)

That way you can make sure you have cleaned up the scene before you go to it.  If this is a linear game where you don’t expect to go back to level1 after you get to level2, then you might want to defer the removing of level1 until you’re already in level2.

Rob

Hi Rob Thanks for your answer! I modified the code based on what you told me but Im still getting the same error on “level2”. “Attempt to call method ‘setLinearVelocity’ (a nil value)” I only get this error when I try to “jump” on the level2 scene. Do you think this might be related to the gravity or addbody functions? 

local physics = require "physics" local composer = require( "composer" ) local scene = composer.newScene() local screenW = display.contentWidth local screenH = display.contentHeight local player local ground local onAir local obstacle local obstacle2 local obstacle3 local playerStartX local playerStartY local playerNextX local playerNextY local star local starEnd -- "scene:create()" function scene:create( event ) local sceneGroup = self.view physics.start() physics.setGravity( 0, 100 ) onAir = false playerStartX = 20 playerStartY = display.contentHeight\*0.5-20 playerNextX = 20 playerNextY = display.contentHeight - 18 player = display.newRect( playerStartX, playerStartY, 20,20 ) player.speed = 3 player.name = "player" player:setFillColor( 1 ) player.isFixedRotation = true --To stop it rotating when jumping etc player.isSleepingAllowed = false --To force it to update and fall off playforms correctly. sceneGroup:insert( player ) ground = display.newRect( 0, display.contentHeight\*0.5-5, display.contentWidth, 5 ) ground.anchorX = 0 ground.anchorY = 0 ground.name = "ground" ground.strokeWidth = 3 ground:setFillColor( 0.5 ) ground:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground ) ground2 = display.newRect( 0, display.contentHeight-5, display.contentWidth, 5 ) ground2.anchorX = 0 ground2.anchorY = 0 ground2.name = "ground" ground2.strokeWidth = 3 ground2:setFillColor( 0.5 ) ground2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground2 ) obstacle = display.newRect( display.contentWidth\*0.5, display.contentHeight\*0.5-46, 20, 40 ) obstacle.anchorX = 0 obstacle.anchorY = 0 obstacle.name = "obstacle" obstacle.strokeWidth = 3 obstacle:setFillColor( 0.5 ) obstacle:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle ) obstacle2 = display.newRect( display.contentWidth\*0.5 - 100, display.contentHeight-46, 20, 40 ) obstacle2.anchorX = 0 obstacle2.anchorY = 0 obstacle2.name = "obstacle" obstacle2.strokeWidth = 3 obstacle2:setFillColor( 0.5 ) obstacle2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle2 ) obstacle3 = display.newRect( display.contentWidth\*0.5 + 60, display.contentHeight-46, 20, 40 ) obstacle3.anchorX = 0 obstacle3.anchorY = 0 obstacle3.name = "obstacle" obstacle3.strokeWidth = 3 obstacle3:setFillColor( 0.5 ) obstacle3:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle3 ) star = display.newRect( display.contentWidth - 10,display.contentHeight\*0.5 - 20, 20, 20 ) star.name = "star" sceneGroup:insert( star ) starEnd = display.newRect( display.contentWidth - 10,display.contentHeight - 20, 20, 20 ) starEnd.name = "starEnd" sceneGroup:insert( starEnd ) physics.addBody( player, "dynamic", { density=1, friction=0.3} ) physics.addBody( ground, "static", { friction=0.5, bounce=0 } ) physics.addBody( ground2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle3, "static", { friction=0.5, bounce=0 } ) physics.addBody( star, "static" ) physics.addBody( starEnd, "static" ) end-- end of the scene --make the player jump when touching the screen function screenTouch( event ) if event.phase == "began" then if onAir == false then player:setLinearVelocity(0,-880) onAir = true end end end function walls( event ) if player.x \< 10 then player.x = 10 elseif player.x \> display.contentWidth-10 then player.x = display.contentWidth-10 end if player.y \< 10 then player.y = 10 elseif player.y \> display.contentHeight then player.y = display.contentHeight end end function onCollision(event) if event.phase == "began" then local name1 = event.object1.name local name2 = event.object2.name if name1 == "player" or name2 == "player" then --Hit the floor, reset vars if name1 == "ground" or name2 == "ground" then onAir = false elseif name1 == "obstacle" or name2 == "obstacle" then timer.performWithDelay(1, moveBackToCheckPoint) elseif name1 == "star" or name2 == "star" then --remove the star if name1 == "star" then --remove the star display.remove(event.object1); event.object1 = nil; else display.remove(event.object2); event.object2 = nil; end timer.performWithDelay(1, goToNextPosition) elseif name1 == "starEnd" or name2 == "starEnd" then goToNextLevel() end end end end function moveBall( event ) player.x = player.x + player.speed end function moveBackToCheckPoint( event ) player.x = playerStartX player.y = playerStartY end function goToNextPosition(event) playerStartX = playerNextX playerStartY = playerNextY player.x = playerNextX player.y = playerNextY end function goToNextLevel( event ) composer.removeScene("level2") composer.gotoScene("level2") end -- "scene:show()" function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then Runtime:addEventListener( "touch", screenTouch ) Runtime:addEventListener("collision",onCollision) Runtime:addEventListener("enterFrame", moveBall) Runtime:addEventListener("enterFrame", walls) -- 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 Runtime:removeEventListener( "touch", screenTouch ) Runtime:removeEventListener("collision",onCollision) Runtime:removeEventListener("enterFrame", moveBall) Runtime:removeEventListener("enterFrame", walls) -- 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. end -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene

You might want to add an additional physics.start() in the show() function and either physics.pause() or .stop() in the hide() scene.

Rob

LIkely its a problem due to when you do things.  If you do something in scene:show() you need to undo it in scene:hide().  However you are deferring removing your runtime listeners and collision listeners until the scene:destroy() event which can come after the scene is off the screen.  Also, I don’t like trying to remove the scene that’s currently on the screen before you goto another scene.  I would take your code out of destroy, put it in hide.  Then leave that scene be and remove the scene you are getting ready to go to.

In other words:

composer.removeScene(“level1”)

composer.gotoScene(“level1”)

composer.removeScene(“level2”)

composer.gotoScene(“level2”)

That way you can make sure you have cleaned up the scene before you go to it.  If this is a linear game where you don’t expect to go back to level1 after you get to level2, then you might want to defer the removing of level1 until you’re already in level2.

Rob

Hi Rob Thanks for your answer! I modified the code based on what you told me but Im still getting the same error on “level2”. “Attempt to call method ‘setLinearVelocity’ (a nil value)” I only get this error when I try to “jump” on the level2 scene. Do you think this might be related to the gravity or addbody functions? 

local physics = require "physics" local composer = require( "composer" ) local scene = composer.newScene() local screenW = display.contentWidth local screenH = display.contentHeight local player local ground local onAir local obstacle local obstacle2 local obstacle3 local playerStartX local playerStartY local playerNextX local playerNextY local star local starEnd -- "scene:create()" function scene:create( event ) local sceneGroup = self.view physics.start() physics.setGravity( 0, 100 ) onAir = false playerStartX = 20 playerStartY = display.contentHeight\*0.5-20 playerNextX = 20 playerNextY = display.contentHeight - 18 player = display.newRect( playerStartX, playerStartY, 20,20 ) player.speed = 3 player.name = "player" player:setFillColor( 1 ) player.isFixedRotation = true --To stop it rotating when jumping etc player.isSleepingAllowed = false --To force it to update and fall off playforms correctly. sceneGroup:insert( player ) ground = display.newRect( 0, display.contentHeight\*0.5-5, display.contentWidth, 5 ) ground.anchorX = 0 ground.anchorY = 0 ground.name = "ground" ground.strokeWidth = 3 ground:setFillColor( 0.5 ) ground:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground ) ground2 = display.newRect( 0, display.contentHeight-5, display.contentWidth, 5 ) ground2.anchorX = 0 ground2.anchorY = 0 ground2.name = "ground" ground2.strokeWidth = 3 ground2:setFillColor( 0.5 ) ground2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( ground2 ) obstacle = display.newRect( display.contentWidth\*0.5, display.contentHeight\*0.5-46, 20, 40 ) obstacle.anchorX = 0 obstacle.anchorY = 0 obstacle.name = "obstacle" obstacle.strokeWidth = 3 obstacle:setFillColor( 0.5 ) obstacle:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle ) obstacle2 = display.newRect( display.contentWidth\*0.5 - 100, display.contentHeight-46, 20, 40 ) obstacle2.anchorX = 0 obstacle2.anchorY = 0 obstacle2.name = "obstacle" obstacle2.strokeWidth = 3 obstacle2:setFillColor( 0.5 ) obstacle2:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle2 ) obstacle3 = display.newRect( display.contentWidth\*0.5 + 60, display.contentHeight-46, 20, 40 ) obstacle3.anchorX = 0 obstacle3.anchorY = 0 obstacle3.name = "obstacle" obstacle3.strokeWidth = 3 obstacle3:setFillColor( 0.5 ) obstacle3:setStrokeColor( 1, 0, 0 ) sceneGroup:insert( obstacle3 ) star = display.newRect( display.contentWidth - 10,display.contentHeight\*0.5 - 20, 20, 20 ) star.name = "star" sceneGroup:insert( star ) starEnd = display.newRect( display.contentWidth - 10,display.contentHeight - 20, 20, 20 ) starEnd.name = "starEnd" sceneGroup:insert( starEnd ) physics.addBody( player, "dynamic", { density=1, friction=0.3} ) physics.addBody( ground, "static", { friction=0.5, bounce=0 } ) physics.addBody( ground2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle2, "static", { friction=0.5, bounce=0 } ) physics.addBody( obstacle3, "static", { friction=0.5, bounce=0 } ) physics.addBody( star, "static" ) physics.addBody( starEnd, "static" ) end-- end of the scene --make the player jump when touching the screen function screenTouch( event ) if event.phase == "began" then if onAir == false then player:setLinearVelocity(0,-880) onAir = true end end end function walls( event ) if player.x \< 10 then player.x = 10 elseif player.x \> display.contentWidth-10 then player.x = display.contentWidth-10 end if player.y \< 10 then player.y = 10 elseif player.y \> display.contentHeight then player.y = display.contentHeight end end function onCollision(event) if event.phase == "began" then local name1 = event.object1.name local name2 = event.object2.name if name1 == "player" or name2 == "player" then --Hit the floor, reset vars if name1 == "ground" or name2 == "ground" then onAir = false elseif name1 == "obstacle" or name2 == "obstacle" then timer.performWithDelay(1, moveBackToCheckPoint) elseif name1 == "star" or name2 == "star" then --remove the star if name1 == "star" then --remove the star display.remove(event.object1); event.object1 = nil; else display.remove(event.object2); event.object2 = nil; end timer.performWithDelay(1, goToNextPosition) elseif name1 == "starEnd" or name2 == "starEnd" then goToNextLevel() end end end end function moveBall( event ) player.x = player.x + player.speed end function moveBackToCheckPoint( event ) player.x = playerStartX player.y = playerStartY end function goToNextPosition(event) playerStartX = playerNextX playerStartY = playerNextY player.x = playerNextX player.y = playerNextY end function goToNextLevel( event ) composer.removeScene("level2") composer.gotoScene("level2") end -- "scene:show()" function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then Runtime:addEventListener( "touch", screenTouch ) Runtime:addEventListener("collision",onCollision) Runtime:addEventListener("enterFrame", moveBall) Runtime:addEventListener("enterFrame", walls) -- 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 Runtime:removeEventListener( "touch", screenTouch ) Runtime:removeEventListener("collision",onCollision) Runtime:removeEventListener("enterFrame", moveBall) Runtime:removeEventListener("enterFrame", walls) -- 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. end -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene

You might want to add an additional physics.start() in the show() function and either physics.pause() or .stop() in the hide() scene.

Rob