Transitioning to and from scenes messes with my physics and variables

I was following an outdated guide on youtube to make a simple side-scrolling jet game that avoids mines, and when the tutorial came to an area of using .purge (or in this case, the updated version of composer.removeScene) that’s when everything started messing up.  So I can get from the mainGame.lua file, to the restart.lua file, but when I try to go back to mainGame, 1 of 2 things will happen. 

  1. Things will transition over smoothly and the game will play.

  2. I get an error, or sometimes physics gets doubled( ie, things go faster)

    21:12:44.104 ERROR: C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:247: physics.start() must be called before physics.stop() 21:12:47.617 ERROR: Runtime error 21:12:47.617 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:31: attempt to call method ‘setLinearVelocity’ (a nil value) 21:12:47.617 stack traceback: 21:12:47.617 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:31: in function ‘activateFlight2’ 21:12:47.617 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:37: in function <C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:35> 21:12:47.617 ?: in function <?:169>

This is without the removeScene.  If I place in a removeScene in restart.lua, I get errors in the first function it finds outside of scene functions (in mainGame) saying I’m trying to compare nil to a number.  I don’t know what else to do.  Let me know if I should include the files to make this post smaller or not. 

So here’s restart.lua:
 

local composer = require( "composer" ) local scene = composer.newScene() -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()" -- ----------------------------------------------------------------------------------- function start(event) if event.phase == "ended" then composer.gotoScene("mainGame", "fade", 500) end end -- ----------------------------------------------------------------------------------- -- Scene event functions -- ----------------------------------------------------------------------------------- -- create() function scene:create( event ) local sceneGroup = self.view -- Code here runs when the scene is first created but has not yet appeared on screen local background = display.newImage("layer-1.png") background.anchorX = 0; background.anchorY = 0 background.x = 0; background.y = 0 ------------------ Dead Bird Animation----------- --||||||||||||||| Bird |||||||||||||||||||||||||| local sheetOptions1 ={width = 561,height = 435,numFrames = 4 } local sheet\_idleBird = graphics.newImageSheet( "deadBird.png", sheetOptions1 ) -- sequences table local sequences\_idleBird = { -- consecutive frames sequence {name = "normalFly",start = 1,count = 4,time = 900,loopCount = 0, }, } deadBird = display.newSprite(sheet\_idleBird, sequences\_idleBird) deadBird.x = 220; deadBird.y = 150; deadBird:scale(0.5,0.5) sceneGroup:insert(background) sceneGroup:insert(deadBird) end -- show() function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen deadBird:play() deadBird:addEventListener("touch", start) end end -- hide() function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is on screen (but is about to go off screen) elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen deadBird:removeEventListener("touch", start) end end -- destroy() function scene:destroy( event ) local sceneGroup = self.view -- Code here runs prior to the removal of scene's view end -- ----------------------------------------------------------------------------------- -- Scene event function listeners -- ----------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ----------------------------------------------------------------------------------- return scene

and here’s my mainGame.lua:

 

local composer = require( "composer" ) local scene = composer.newScene() local physics = require "physics" physics.start() -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()" -- ----------------------------------------------------------------------------------- function scrollEnvironment(self, event) if self.x \< -1145 then self.x = 1157 else self.x = self.x - self.speed end end function moveObstacles(self, event) if self.x \< -50 then obstacleCounter = math.random(1,4) self.x = 500 elseif (obstacleCounter == self.counter)then self.x = self.x - self.speed end end function boostPowerup(self, event) end function activateFlight2(self) self:setLinearVelocity(0,0) self:applyForce(0,-10,self.x,self.y) end function touchScreen(event) if event.phase == "began" then activateFlight2(bird) end end function onCollision(event) if event.phase == "began" then composer.gotoScene("restart", "fade", 400) end end -- ----------------------------------------------------------------------------------- -- Scene event functions -- ----------------------------------------------------------------------------------- -- create() function scene:create( event ) local sceneGroup = self.view -- Code here runs when the scene is first created but has not yet appeared on screen restartCounter = false; obstacleCounter = math.random(1,4); groundSpeed = 7; --||||||||| Background Image ||||||||||||||||||| local background = display.newImage("layer-1.png") background.anchorX = 0; background.anchorY = 0 background.x = 0; background.y = 0 background:scale(0.4,0.4) --|||||||||Cieling and flooring||||||||||||||||||| ceiling = display.newImage("testInvisTile.png") ceiling.x = 0; ceiling.y = 10 flooring = display.newImage("testInvisTile.png") flooring.anchorX = 0; flooring.anchorY = 1; flooring.x = 0; flooring.y = 320 --|||||||||||||||| Forest Display |||||||||||||| shrubs1 = display.newImage("layer-2.png") shrubs1.anchorX = 0; shrubs1.anchorY = 1; shrubs1.x = 0; shrubs1.y = 320 shrubs1:scale(0.4,0.4) shrubs1.speed = groundSpeed - 4 shrubs2 = display.newImage("layer-2.png") shrubs2.anchorX = 0; shrubs2.anchorY = 1; shrubs2.x = 1157; shrubs2.y = 320 shrubs2:scale(0.4,0.4) shrubs2.speed = groundSpeed - 4 forest1 = display.newImage("layer-3.png") forest1.anchorX = 0; forest1.anchorY = 1; forest1.x = 0; forest1.y = 320 forest1:scale(0.4,0.4) forest1.speed = groundSpeed - 2 forest2 = display.newImage("layer-3.png") forest2.anchorX = 0; forest2.anchorY = 1; forest2.x = 1157; forest2.y = 320 forest2:scale(0.4,0.4) forest2.speed = groundSpeed - 2 --||||||||||||||| Ground Display ||||||||||||||| ground1 = display.newImage("layer-5.png") ground1.anchorX = 0; ground1.anchorY = 1 ground1.x = 0; ground1.y = 300 ground1:scale(0.4, 0.4) ground1.speed = groundSpeed ground2 = display.newImage("layer-5.png") ground2.anchorX = 0; ground2.anchorY = 1 ground2.x = 1157; ground2.y = 300 ground2:scale(0.4, 0.4) ground2.speed = groundSpeed --||||||||||||||| Bird |||||||||||||||||||||||||| local sheetOptions1 ={width = 561,height = 435,numFrames = 4 } local sheet\_idleBird = graphics.newImageSheet( "testingBirdFly3.png", sheetOptions1 ) -- sequences table local sequences\_idleBird = { -- consecutive frames sequence {name = "normalFly",start = 1,count = 4,time = 900,loopCount = 0, }, -- next sequence (non-consecutive frames) {name = "fastFly",start = 1,count = 4,time = 100,loopCount = 0 }, } bird = display.newSprite(sheet\_idleBird, sequences\_idleBird) bird.x = 50; bird.y = 100; bird:scale(0.1,0.1) bird.width = 40; bird.height = 40 --|||||||||||||| Obstacles |||||||||||||||||||||||| obstacleTopSmall = display.newImage("obstacle hanging sharp wood.png") obstacleTopSmall.x = math.random(550,900); obstacleTopSmall.y = 50; obstacleTopSmall.speed = groundSpeed; obstacleTopSmall.counter = 1 obstacleTopSmall:scale(0.8,0.8) obstacleTopSmall.width = 40; obstacleTopSmall.height = 100; obstacleTopBig = display.newImage("obstacle hanging sharp wood.png") obstacleTopBig.x = math.random(550,1100); obstacleTopBig.y = 50; obstacleTopBig.speed = groundSpeed obstacleTopBig.counter = 2 obstacleTopBig:scale(0.8,1.2) obstacleTopBig.width = 40; obstacleTopBig.height = 100; obstacleBottomBig = display.newImage("obstacle tall sharp wood.png") obstacleBottomBig.anchorX = 0; obstacleBottomBig.anchorY = 1 obstacleBottomBig.x = math.random(550,900); obstacleBottomBig.y = 270; obstacleBottomBig.speed = groundSpeed obstacleBottomBig.counter = 3 obstacleBottomBig:scale(0.8,0.8) obstacleBottomBig.width = 70; obstacleBottomBig.height = 200; obstacleBottomSmall = display.newImage("obstacle short sharp wood.png") obstacleBottomSmall.anchorX = 0; obstacleBottomSmall.anchorY = 1 obstacleBottomSmall.x = math.random(550,900); obstacleBottomSmall.y = 270; obstacleBottomSmall.speed = groundSpeed obstacleBottomSmall.counter = 4 obstacleBottomSmall:scale(0.8,0.8) obstacleBottomSmall.width = 40; obstacleBottomSmall.height = 100; sceneGroup:insert(background) sceneGroup:insert(ceiling) sceneGroup:insert(flooring) sceneGroup:insert(shrubs1) sceneGroup:insert(shrubs2) sceneGroup:insert(flooring) sceneGroup:insert(forest1) sceneGroup:insert(forest2) sceneGroup:insert(ground1) sceneGroup:insert(ground2) sceneGroup:insert(bird) sceneGroup:insert(obstacleTopSmall) sceneGroup:insert(obstacleTopBig) sceneGroup:insert(obstacleBottomBig) sceneGroup:insert(obstacleBottomSmall) end -- show() function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) bird.x = 50; bird.y = 100; obstacleTopSmall.x = 500; obstacleTopBig.x = 500; obstacleBottomBig.x = 500; obstacleBottomSmall.x = 500; obstacleCounter = math.random(1,4); elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen physics.start() physics.addBody(bird, "dynamic", {density=.1, bounce=0.1, friction=.2, radius=13}) physics.addBody(obstacleTopSmall, "static", {density=.1, bounce=0.1, friction=.2}) physics.addBody(obstacleTopBig, "static", {density=.1, bounce=0.1, friction=.2}) physics.addBody(obstacleBottomBig, "static", {density=.1, bounce=0.1, friction=.2}) physics.addBody(obstacleBottomSmall, "static", {density=.1, bounce=0.1, friction=.2}) physics.addBody(ceiling, "static", {density=.1, bounce=0.1, friction=.2}) physics.addBody(flooring, "static", {density=.1, bounce=0.1, friction=.2}) bird:play() -- play the new sequence shrubs1.enterFrame = scrollEnvironment shrubs2.enterFrame = scrollEnvironment forest1.enterFrame = scrollEnvironment forest2.enterFrame = scrollEnvironment ground1.enterFrame = scrollEnvironment ground2.enterFrame = scrollEnvironment obstacleTopSmall.enterFrame = moveObstacles obstacleTopBig.enterFrame = moveObstacles obstacleBottomBig.enterFrame = moveObstacles obstacleBottomSmall.enterFrame = moveObstacles Runtime:addEventListener("touch", touchScreen) Runtime:addEventListener("collision", onCollision) Runtime:addEventListener("enterFrame", shrubs1) Runtime:addEventListener("enterFrame", shrubs2) Runtime:addEventListener("enterFrame", forest1) Runtime:addEventListener("enterFrame", forest2) Runtime:addEventListener("enterFrame", ground1) Runtime:addEventListener("enterFrame", ground2) Runtime:addEventListener("enterFrame", obstacleTopSmall) Runtime:addEventListener("enterFrame", obstacleTopBig) Runtime:addEventListener("enterFrame", obstacleBottomBig) Runtime:addEventListener("enterFrame", obstacleBottomSmall) end end -- hide() function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is on screen (but is about to go off screen) elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen Runtime:removeEventListener("touch", touchScreen) Runtime:removeEventListener("collision", onCollision) Runtime:removeEventListener("enterFrame", shrubs1) Runtime:removeEventListener("enterFrame", shrubs2) Runtime:removeEventListener("enterFrame", forest1) Runtime:removeEventListener("enterFrame", forest2) Runtime:removeEventListener("enterFrame", ground1) Runtime:removeEventListener("enterFrame", ground2) Runtime:removeEventListener("enterFrame", obstacleTopSmall) Runtime:removeEventListener("enterFrame", obstacleTopBig) Runtime:removeEventListener("enterFrame", obstacleBottomBig) Runtime:removeEventListener("enterFrame", obstacleBottomSmall) physics.stop() end end -- destroy() function scene:destroy( event ) local sceneGroup = self.view -- Code here runs prior to the removal of scene's view end -- ----------------------------------------------------------------------------------- -- Scene event function listeners -- ----------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ----------------------------------------------------------------------------------- return scene

To simplify trouble shooting this, please change this in restart.lua to:

function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen deadBird:play() deadBird:addEventListener("touch", start) composer.removeScene("mainGame") --\<------- Added line end end

And lets focus on trouble shooting the errors caused by that and not worry about problems when you don’t have it.

Next in both scenes all of your functions in the main chunk are global functions. These really should be local functions, in other words:

local function start( event )

instead of:

function start( event )

The functions that start with scene: are part of the scene object and those would NOT get a local in front of them.

Robo

Thank you for replying.  So I made the changes, and it goes to a function in mainGame that isn’t scene related, and gets a nil error.
Also note-worthy of saying, this happens 40% of the time when I hit restart in-game.  So it’s not 100% of the time this error occurs.
 

14:40:58.782 ERROR: Runtime error 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:32: attempt to call method 'setLinearVelocity' (a nil value) 14:40:58.782 stack traceback: 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:32: in function 'activateFlight2' 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:38: in function \<C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:36\> 14:40:58.782 ?: in function \<?:169\>

Humor me and put:

local bird

at the top of the mainGame.lua scene just after  you call:

local scene = composer.newScene()

and see if that changes anything.

Rob

Was going strong for 5 games, but eventually the error popped up again.

Also, on a different issue, I popped in a print(“Should see this once per game”) in the scene:show() ‘did’ phase, and just when the physics got doubled, I saw “Should see this once per game” popped up twice in that last round.

Well that error is telling me you’re tapping the screen at some point where “bird” doesn’t exist. When it errored could you have gotten a tap in before the bird got re-created?  Or perhaps you’re getting a different error?

Rob

My mouse does sometimes double left-click, but is that what is causing the problem?  Should I put a boolean if-check inside restart.lua to see if it runs only once?

**edit**

So there’s a print() in both show’s for mainGame and Restart ‘did’ phase.  I wanted to see if they were each being called only ONCE as it went from game, to restart, back to game, etc.  This is what I get.

**edit**
After more testing, the game is fine when each game/restart show is called only once. when it happens twice in a row, I get the error.

**edit**
I believe I fixed the problem.  So in mainGame’s scene:hide, I had the removeEventListeners in the ‘did’ phase, which meant that it could still take touch input during the ‘will’ phase, which sent it to the Restart screen twice.  So I moved the removeEventListeners to the scene:hide ‘will’ phase and so far, I haven’t seen any duplicates, nor errors. 

15:24:13.616 Should see this only once. 15:24:18.974 Restart - Show - should see this once. 15:24:19.116 Restart - Show - should see this once. 15:24:29.056 Should see this only once. 15:24:31.952 Restart - Show - should see this once. 15:24:37.146 Should see this only once. 15:24:44.837 Restart - Show - should see this once. 15:24:51.880 Should see this only once. 15:24:54.727 Restart - Show - should see this once. 15:24:58.743 Should see this only once. 15:25:04.235 Restart - Show - should see this once. 15:25:04.300 Restart - Show - should see this once. 15:25:07.774 Should see this only once. 15:25:08.739 Should see this only once. 15:25:09.038 Restart - Show - should see this once.

Look like most of the variables are not declared as ‘local’, and other files may overwrite it. Also notice you have alot of ‘enterFrame’. Not sure whether it will impact performance.

Try to check whether it is nil when doing something. 

if ground1 ~= nil then ground1.enterFrame = scrollEnvironment end function activateFlight2(self) &nbsp;&nbsp;&nbsp;&nbsp;if self ~= nil then self:setLinearVelocity(0,0) end &nbsp;&nbsp;&nbsp;&nbsp;if self ~= nil then self:applyForce(0,-10,self.x,self.y) end end

Since your pc-mouse may be double-clicking, try putting a short timer to avoid double or fast touches

local isBusy = false function touchScreen(event) if event.phase == "began" then if isBusy == false then activateFlight2(bird) end isBusy = true local tmpTimer = timer.performWithDelay( 100, function() isBusy = false end ) -- Remember to stop this timer when exit scene. end end

Hope it helps.

Done and done.  No more crashes as of late. Thanks for all the help.  

Quick question, I do plan to add more to the game, so how would I go about limiting the amount of enterFrame callings?

-- Just call the 'enterFrame' once, and do all the logic in it -- Note : It can be 30fps (default) or 60fps. local function allLogic( event ) -- Do your checks in here for shrubs1, forest1, etc... end Runtime:removeEventListener("enterFrame", allLogic )

Just a sample based on https://docs.coronalabs.com/api/event/enterFrame/index.html

This thread is officially Solved.  So thank you guys.

I’ll just continue to ask questions but you don’t need to answer them if you don’t want to. 
 

In my global collision event, how do I differentiate between obstacles and power-ups?

 

local function onCollision(event) if event.phase == "began" then composer.gotoScene("restart", "fade", 400) end end

It’s currently used to detect collision with obstacles, and sends us to a restart scene. 

I want to somehow detect a collision with boostPowerUp that will turn a bird.isBoost = true

Check our our getting started guide.  The collision handling starts here:

https://docs.coronalabs.com/guide/programming/03/index.html#collision-handling

But you may want to read the while guide so you’re familiar with how things are setup.

Rob

Is there a way to change the simulator settings to see what my app would look like if I put it on different devices with different resolutions?  Some of the coordinates are hard-coded and I’m afraid things will look odd on bigger devices. 

Also, can someone point me in the direction of making this app Iphone-ready?  I’m close to finishing and I really have no idea what to do next, but I know that I want to put it up on the markets. 

You can use different skins in the simulator to see how your app will be have on different devices. You can also set custom resolutions if you want to test on a skin that we don’t support.  From the simulator’s main menu do:

Window->View

and pick your choice from there.

As far as what to do next, test on a real device. There are quite a few things that behave differently between the simulator and a real device (like case sensitive file names – which should be producing warnings in the simulator’s console log). If you’re using Ads, GameCenter, In-App purchases or anything like that, those can only be tested on a device or the Xcode simulator (not the Corona Simulator).

Rob

I’ve been adding sound and music to the game, and some work and some don’t.   They are all .wav format and I get this error for at least 3 sound/music files while the others work fine. Any ideas?

 

23:49:11.587 WARNING: C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:505: audio.loadStream() failed to create stream 'Inspired (Happy-Pop).wav' 23:49:14.508 WARNING: C:\Users\Didier\Documents\Corona Projects\SpeedyBird\restart.lua:106: audio.loadSound() failed to create sound 'menuSelect.wav' 23:49:14.518 WARNING: C:\Users\Didier\Documents\Corona Projects\SpeedyBird\restart.lua:107: audio.loadStream() failed to create stream 'funkyRooster.wav'

Some of the code: 

 

menuSelect = audio.loadSound("menuSelect.wav") restartSound = audio.loadStream("funkyRooster.wav")

audio.play(restartSound, {channel = 2})

 audio.stop(1) audio.stop(2) audio.dispose(menuSelect) audio.dispose(restartSound) menuSelect = nil restartSound = nil

HI @neviah.

Your latest question is doing something called “hijacking the thread”. We discourage this for a few reasons. First people search for forum posts looking for answers. If they search for audio questions and this thread shows up, they become confused. They read the first few posts and may not scroll all the way down to this point and this creates frustration for them. The other side of that is someone is looking for questions on transitioning to and from scenes, reads the thread and finds a bunch of audio talk. Again this frustrates the community.

When you have an un-related question to the thread, please start a new thread. We also have specific sub-forums to discuss audio. I would recommend creating a new thread is the audio subforum.

Rob

To simplify trouble shooting this, please change this in restart.lua to:

function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen deadBird:play() deadBird:addEventListener("touch", start) composer.removeScene("mainGame") --\<------- Added line end end

And lets focus on trouble shooting the errors caused by that and not worry about problems when you don’t have it.

Next in both scenes all of your functions in the main chunk are global functions. These really should be local functions, in other words:

local function start( event )

instead of:

function start( event )

The functions that start with scene: are part of the scene object and those would NOT get a local in front of them.

Robo

Thank you for replying.  So I made the changes, and it goes to a function in mainGame that isn’t scene related, and gets a nil error.
Also note-worthy of saying, this happens 40% of the time when I hit restart in-game.  So it’s not 100% of the time this error occurs.
 

14:40:58.782 ERROR: Runtime error 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:32: attempt to call method 'setLinearVelocity' (a nil value) 14:40:58.782 stack traceback: 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:32: in function 'activateFlight2' 14:40:58.782 C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:38: in function \<C:\Users\Didier\Documents\Corona Projects\SpeedyBird\mainGame.lua:36\> 14:40:58.782 ?: in function \<?:169\>

Humor me and put:

local bird

at the top of the mainGame.lua scene just after  you call:

local scene = composer.newScene()

and see if that changes anything.

Rob

Was going strong for 5 games, but eventually the error popped up again.

Also, on a different issue, I popped in a print(“Should see this once per game”) in the scene:show() ‘did’ phase, and just when the physics got doubled, I saw “Should see this once per game” popped up twice in that last round.