Reload Scene but then the error of SetLinear Velocity comes up...

I set another scene after its gameover on a retry image, it goes to menu scene then it goes back to level1 Scene but then comes the error:

attempt to call method ‘setLinearVelocity’ (a nil value)

I have the reload in Menu Scene:

local function onPlayBtnRelease() -- go to level1.lua scene storyboard.removeScene("level1") storyboard.gotoScene( "level1", "fade", 500 ) return true -- indicates successful touch end

And i understand that it happens when there is no physicsadd body in the object but it is reloading and it is having assign the physics body again, so why it is not working?

Please help.

Here is my code:

----------------------------------------------------------------------------------------- -- -- level1.lua -- ----------------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local scene = storyboard.newScene() -- include Corona's "physics" library local physics = require "physics" physics.start(); physics.pause() physics.setGravity(0,25.8) -------------------------------------------- local function onnextBtnRelease() storyboard.reloadScene("level1") storyboard.gotoScene("menu","fade",1000) return true end -- forward declarations and other locals local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 --local retryBtn ----------------------------------------------------------------------------------------- -- BEGINNING OF YOUR IMPLEMENTATION -- -- NOTE: Code outside of listener functions (below) will only be executed once, -- unless storyboard.removeScene() is called. -- ----------------------------------------------------------------------------------------- -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view local grass1={} local retryBtn local counter=0 local crate local linearv=setLinearVelocity -- create a grey rectangle as the backdrop local background = display.newRect( 0, 0, screenW, screenH ) background.anchorX = 0 background.anchorY = 0 background:setFillColor( .5 ) -- make a crate (off-screen), position it, and rotate slightly -- create a grass object and add physics (with custom shape) local grass = display.newImageRect( "grass.png", screenW, 82 ) grass.anchorX = 0 grass.anchorY = 1 grass.x, grass.y = 0, display.contentHeight retryBtn = display.newImageRect("retry2.png",264,42) retryBtn.x,retryBtn.y=display.contentWidth\*0.5,140 -- event listener function retryBtn.isVisible=false --retryBtn:addEventListener( "touch", onretryBtnRelease) crate = display.newImageRect( "crate.png", 25,25 ) crate.x, crate.y = 160, 380 crate.rotation = 15 crate.name="crate" physics.addBody( crate, { density=0.1, friction=0.3, bounce=0.3 } ) -- add physics to the crate -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) local grassShape = { -halfW,-34, halfW,-34, halfW,34, -halfW,34 } physics.addBody( grass, "static", { friction=0.3, shape=grassShape } ) -- all display objects must be inserted into group group:insert( background ) group:insert( grass) group:insert( crate ) group:insert(retryBtn) for i=1, 100,1 do grass1[i] = display.newImageRect( "grass.png", 100, 20 ) grass1[i].x, grass1[i].y = -50+math.random(0,350), -1500+math.random(0,1850) grass1[i].name="grass1" -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) physics.addBody( grass1[i], "static", { friction=0.3}) group:insert(grass1[i]) end function crate:enterFrame() function dashmove(event) if crate then if event.phase == "began" then bx = event.x by = event.y elseif event.phase == "moved" then activateDash = true elseif event.phase == "ended" then if activateDash then if \_G.gX == 0 and \_G.gY ~= 0 then crate:setLinearVelocity(event.x-bx,0) elseif \_G.gX ~= 0 and \_G.gY == 0 then crate:setLinearVelocity(0,event.y-by) else crate:setLinearVelocity(event.x-bx,event.y-by) end activateDash = false end end end end Runtime:addEventListener("touch",dashmove) end Runtime:addEventListener("enterFrame",crate); function gamelost() print("llegue aqui") print("".. counter) if (retryBtn.isVisible==true) then retryBtn:addEventListener("touch",onnextBtnRelease) physics.stop() end end -- if you comment out his line then the scrollview will work function onCollision(event) if(event.object1.name =="grass1" and event.object2.name == "crate" or event.object1.name == "crate" and event.object2.name == "grass1") then --dashmove=false print("".. counter) gameover=display.newImageRect("youlost1.png",264,42) gameover.x = display.contentWidth \* 0.5 gameover.y = 100 group:insert(gameover) retryBtn.isVisible=true gamelost() -- Update the score --score = score + 1 --txt\_score.text = "Score: "..score -- Make the objects invisible --event.object1.alpha = 0 --event.object2.alpha = 0 -- Cancel the transitions on the object transition.cancel(event.object1.trans) transition.cancel(event.object2.trans) -- Then remove the object after 1 cycle. Never remove display objects in the middle of collision detection. --local function removeObjects() -- display.remove(event.object1) -- display.remove(event.object2) --end --timer.performWithDelay(1, removeObjects, 1) end end --retryBtn:addEventListener( "touch", onretryBtnRelease) end --Runtime:addEventListener("collision",onCollision) -- Called immediately after scene has moved onscreen: function scene:willEnterScene(event) local group=self.view physics.start() end function scene:enterScene( event ) local group = self.view physics.start() --crate:addEventListener("touch", startDrag) Runtime:addEventListener("collision",onCollision) --onComplete =function(onCollision) --timer.performWithDelay(1,gamelost,0) --crate:addEventListener("touch", startDrag) --end --end end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view physics.stop() end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroyScene( event ) local group = self.view if retryBtn then retryBtn:removeSelf() -- widgets must be manually removed retryBtn = nil end package.loaded[physics] = nil physics = nil if grass then grass:removeSelf(); grass=nil end if grass1 then for i=1, #grass1, 1 do grass1[i].removeSelf(); end end if crate then crate:removeSelf(); crate=nil end end ----------------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION ----------------------------------------------------------------------------------------- -- "createScene" event is dispatched if scene's view does not exist scene:addEventListener( "createScene", scene ) -- "enterScene" event is dispatched whenever scene transition has finished scene:addEventListener( "enterScene", scene ) -- "exitScene" event is dispatched whenever before next scene's transition begins scene:addEventListener( "exitScene", scene ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroyScene", scene ) ----------------------------------------------------------------------------------------- return scene

I made some prints after the physics has been added to the object crate and it is indeed adding physics to the body in the line physics.addbody(crate…

So then why this error comes up?

The scene is being completely reloaded so it is calling the scene Level1 again from scratch. I dont get it.

Please help me. :frowning:

Thanks

Edit:

Runtime error e:\game\thegame\level1.lua:114: attempt to call method 'setLinearVelocity' (a nil value) stack traceback: [C]: in function 'setLinearVelocity' e:\game\thegame\level1.lua:114: in function \<e:\game\thegame\level1.lua:98\> ?: in function \<?:2

Why nobody answers my question? :(  :o

I saw a similar post when i was looking up for this error in google and it took me to a post in this forum and Rob said it has to do with adding physics to the body. And as u can see in my code, it is indeed adding physics when it remove the scene then it loads it again.

Hi @zineshult,

You are right about your error. 

However your code arrangement/sequence is important in storyboard.

I removed/moved some parts around so it will work.

But this may be the main reasons.

1- you next button fuction you are calling reload scene and gotoscene. You have to create seperate button/function to go to menu scene.

2 - for reload scene you may need to purge scene on exitScene or willexitScene function.

3-  you have too many physics.start/stop call.

Here is your edited code. It should work but i do not do a proper “clean up”.

----------------------------------------------------------------------------------------- -- -- level1.lua -- ----------------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local scene = storyboard.newScene() local crate local gameover -------------------------------------------- local function onnextBtnRelease() storyboard.reloadScene("level1") --storyboard.gotoScene("menu","fade",1000) return true end -- forward declarations and other locals local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 --local retryBtn -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view local grass1={} local retryBtn local counter=0 --local crate local linearv=setLinearVelocity local physics = require "physics" physics.start(); --physics.pause() physics.setGravity(0,25.8) -- create a grey rectangle as the backdrop local background = display.newRect( 0, 0, screenW, screenH ) background.anchorX = 0 background.anchorY = 0 background:setFillColor( .5 ) -- make a crate (off-screen), position it, and rotate slightly -- create a grass object and add physics (with custom shape) local grass = display.newImageRect( "grass.png", screenW, 82 ) grass.anchorX = 0 grass.anchorY = 1 grass.x, grass.y = 0, display.contentHeight retryBtn = display.newImageRect("retry2.png",264,42) retryBtn.x,retryBtn.y=display.contentWidth\*0.5,140 -- event listener function retryBtn.isVisible=false --retryBtn:addEventListener( "touch", onretryBtnRelease) crate = display.newImageRect( "crate.png", 25,25 ) crate.x, crate.y = 160, 380 crate.rotation = 15 crate.name="crate" physics.addBody( crate, { density=0.1, friction=0.3, bounce=0.3 } ) -- add physics to the crate -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) local grassShape = { -halfW,-34, halfW,-34, halfW,34, -halfW,34 } physics.addBody( grass, "static", { friction=0.3, shape=grassShape } ) gameover=display.newImageRect("youlost1.png",264,42) gameover.x = display.contentWidth \* 0.5 gameover.y = 100 gameover.alpha = 0 -- all display objects must be inserted into group group:insert( background ) group:insert( grass) group:insert( crate ) group:insert(retryBtn) group:insert(gameover) for i=1, 100,1 do grass1[i] = display.newImageRect( "grass.png", 100, 20 ) grass1[i].x, grass1[i].y = -50+math.random(0,350), -1500+math.random(0,1850) grass1[i].name="grass1" -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) physics.addBody( grass1[i], "static", { friction=0.3}) group:insert(grass1[i]) end function crate:enterFrame() function dashmove(event) if crate then if event.phase == "began" then bx = event.x by = event.y print("CHECK : ", bx, by, event.x, event.y) elseif event.phase == "moved" then activateDash = true elseif event.phase == "ended" then if activateDash then print("CHECK2 : ", bx, by, event.x, event.y) if \_G.gX == 0 and \_G.gY ~= 0 then crate:setLinearVelocity(event.x-bx,0) elseif \_G.gX ~= 0 and \_G.gY == 0 then crate:setLinearVelocity(0,event.y-by) else crate:setLinearVelocity(event.x-bx,event.y-by) end activateDash = false end end end end Runtime:addEventListener("touch",dashmove) end Runtime:addEventListener("enterFrame",crate); function gamelost() print("llegue aqui") print("".. counter) if (retryBtn.isVisible==true) then retryBtn:addEventListener("touch",onnextBtnRelease) --timer.performWithDelay( 100 , physics.stop()) end end -- if you comment out his line then the scrollview will work function onCollision(event) if(event.object1.name =="grass1" and event.object2.name == "crate" or event.object1.name == "crate" and event.object2.name == "grass1") then --dashmove=false print("".. counter) gameover.alpha = 1 retryBtn.isVisible=true -- Update the score --score = score + 1 --txt\_score.text = "Score: "..score -- Make the objects invisible --event.object1.alpha = 0 --event.object2.alpha = 0 -- Cancel the transitions on the object transition.cancel(event.object1.trans) transition.cancel(event.object2.trans) -- Then remove the object after 1 cycle. Never remove display objects in the middle of collision detection. local function removeObjects() display.remove(event.object1) display.remove(event.object2) gamelost() end timer.performWithDelay(1, removeObjects, 1) end end --retryBtn:addEventListener( "touch", onretryBtnRelease) end --Runtime:addEventListener("collision",onCollision) -- Called immediately after scene has moved onscreen: function scene:willEnterScene(event) local group=self.view --physics.start() end function scene:enterScene( event ) local group = self.view --physics.start() --crate:addEventListener("touch", startDrag) Runtime:addEventListener("collision",onCollision) --onComplete =function(onCollision) --timer.performWithDelay(1,gamelost,0) --crate:addEventListener("touch", startDrag) --end --end end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view storyboard.purgeScene("level1" ) --physics.stop() end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroyScene( event ) local group = self.view if retryBtn then retryBtn:removeSelf() -- widgets must be manually removed retryBtn = nil end --package.loaded[physics] = nil --physics = nil if grass then grass:removeSelf(); grass=nil end if grass1 then for i=1, #grass1, 1 do grass1[i].removeSelf(); end end --if crate then --crate:removeSelf(); --crate=nil --end physics.stop() end scene:addEventListener( "createScene", scene ) scene:addEventListener( "enterScene", scene ) scene:addEventListener( "exitScene", scene ) scene:addEventListener( "destroyScene", scene ) ----------------------------------------------------------------------------------------- return scene

Cheer Up!

burhan

Thanks Burhan, but i found the problem was to declare global, the crate, _G.crate and it works when the scene is changed to another one and then comes back to the same.

Hi @zineshult,

Although you manage to solve your problem but i do not think that is the best solution.

You should avoid using global where possible.

Read the tutorial by Rob to understand why.

http://coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

Have fun!

burhan

I made some prints after the physics has been added to the object crate and it is indeed adding physics to the body in the line physics.addbody(crate…

So then why this error comes up?

The scene is being completely reloaded so it is calling the scene Level1 again from scratch. I dont get it.

Please help me. :frowning:

Thanks

Edit:

Runtime error e:\game\thegame\level1.lua:114: attempt to call method 'setLinearVelocity' (a nil value) stack traceback: [C]: in function 'setLinearVelocity' e:\game\thegame\level1.lua:114: in function \<e:\game\thegame\level1.lua:98\> ?: in function \<?:2

Why nobody answers my question? :(  :o

I saw a similar post when i was looking up for this error in google and it took me to a post in this forum and Rob said it has to do with adding physics to the body. And as u can see in my code, it is indeed adding physics when it remove the scene then it loads it again.

Hi @zineshult,

You are right about your error. 

However your code arrangement/sequence is important in storyboard.

I removed/moved some parts around so it will work.

But this may be the main reasons.

1- you next button fuction you are calling reload scene and gotoscene. You have to create seperate button/function to go to menu scene.

2 - for reload scene you may need to purge scene on exitScene or willexitScene function.

3-  you have too many physics.start/stop call.

Here is your edited code. It should work but i do not do a proper “clean up”.

----------------------------------------------------------------------------------------- -- -- level1.lua -- ----------------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local scene = storyboard.newScene() local crate local gameover -------------------------------------------- local function onnextBtnRelease() storyboard.reloadScene("level1") --storyboard.gotoScene("menu","fade",1000) return true end -- forward declarations and other locals local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 --local retryBtn -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view local grass1={} local retryBtn local counter=0 --local crate local linearv=setLinearVelocity local physics = require "physics" physics.start(); --physics.pause() physics.setGravity(0,25.8) -- create a grey rectangle as the backdrop local background = display.newRect( 0, 0, screenW, screenH ) background.anchorX = 0 background.anchorY = 0 background:setFillColor( .5 ) -- make a crate (off-screen), position it, and rotate slightly -- create a grass object and add physics (with custom shape) local grass = display.newImageRect( "grass.png", screenW, 82 ) grass.anchorX = 0 grass.anchorY = 1 grass.x, grass.y = 0, display.contentHeight retryBtn = display.newImageRect("retry2.png",264,42) retryBtn.x,retryBtn.y=display.contentWidth\*0.5,140 -- event listener function retryBtn.isVisible=false --retryBtn:addEventListener( "touch", onretryBtnRelease) crate = display.newImageRect( "crate.png", 25,25 ) crate.x, crate.y = 160, 380 crate.rotation = 15 crate.name="crate" physics.addBody( crate, { density=0.1, friction=0.3, bounce=0.3 } ) -- add physics to the crate -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) local grassShape = { -halfW,-34, halfW,-34, halfW,34, -halfW,34 } physics.addBody( grass, "static", { friction=0.3, shape=grassShape } ) gameover=display.newImageRect("youlost1.png",264,42) gameover.x = display.contentWidth \* 0.5 gameover.y = 100 gameover.alpha = 0 -- all display objects must be inserted into group group:insert( background ) group:insert( grass) group:insert( crate ) group:insert(retryBtn) group:insert(gameover) for i=1, 100,1 do grass1[i] = display.newImageRect( "grass.png", 100, 20 ) grass1[i].x, grass1[i].y = -50+math.random(0,350), -1500+math.random(0,1850) grass1[i].name="grass1" -- define a shape that's slightly shorter than image bounds (set draw mode to "hybrid" or "debug" to see) physics.addBody( grass1[i], "static", { friction=0.3}) group:insert(grass1[i]) end function crate:enterFrame() function dashmove(event) if crate then if event.phase == "began" then bx = event.x by = event.y print("CHECK : ", bx, by, event.x, event.y) elseif event.phase == "moved" then activateDash = true elseif event.phase == "ended" then if activateDash then print("CHECK2 : ", bx, by, event.x, event.y) if \_G.gX == 0 and \_G.gY ~= 0 then crate:setLinearVelocity(event.x-bx,0) elseif \_G.gX ~= 0 and \_G.gY == 0 then crate:setLinearVelocity(0,event.y-by) else crate:setLinearVelocity(event.x-bx,event.y-by) end activateDash = false end end end end Runtime:addEventListener("touch",dashmove) end Runtime:addEventListener("enterFrame",crate); function gamelost() print("llegue aqui") print("".. counter) if (retryBtn.isVisible==true) then retryBtn:addEventListener("touch",onnextBtnRelease) --timer.performWithDelay( 100 , physics.stop()) end end -- if you comment out his line then the scrollview will work function onCollision(event) if(event.object1.name =="grass1" and event.object2.name == "crate" or event.object1.name == "crate" and event.object2.name == "grass1") then --dashmove=false print("".. counter) gameover.alpha = 1 retryBtn.isVisible=true -- Update the score --score = score + 1 --txt\_score.text = "Score: "..score -- Make the objects invisible --event.object1.alpha = 0 --event.object2.alpha = 0 -- Cancel the transitions on the object transition.cancel(event.object1.trans) transition.cancel(event.object2.trans) -- Then remove the object after 1 cycle. Never remove display objects in the middle of collision detection. local function removeObjects() display.remove(event.object1) display.remove(event.object2) gamelost() end timer.performWithDelay(1, removeObjects, 1) end end --retryBtn:addEventListener( "touch", onretryBtnRelease) end --Runtime:addEventListener("collision",onCollision) -- Called immediately after scene has moved onscreen: function scene:willEnterScene(event) local group=self.view --physics.start() end function scene:enterScene( event ) local group = self.view --physics.start() --crate:addEventListener("touch", startDrag) Runtime:addEventListener("collision",onCollision) --onComplete =function(onCollision) --timer.performWithDelay(1,gamelost,0) --crate:addEventListener("touch", startDrag) --end --end end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view storyboard.purgeScene("level1" ) --physics.stop() end -- If scene's view is removed, scene:destroyScene() will be called just prior to: function scene:destroyScene( event ) local group = self.view if retryBtn then retryBtn:removeSelf() -- widgets must be manually removed retryBtn = nil end --package.loaded[physics] = nil --physics = nil if grass then grass:removeSelf(); grass=nil end if grass1 then for i=1, #grass1, 1 do grass1[i].removeSelf(); end end --if crate then --crate:removeSelf(); --crate=nil --end physics.stop() end scene:addEventListener( "createScene", scene ) scene:addEventListener( "enterScene", scene ) scene:addEventListener( "exitScene", scene ) scene:addEventListener( "destroyScene", scene ) ----------------------------------------------------------------------------------------- return scene

Cheer Up!

burhan

Thanks Burhan, but i found the problem was to declare global, the crate, _G.crate and it works when the scene is changed to another one and then comes back to the same.

Hi @zineshult,

Although you manage to solve your problem but i do not think that is the best solution.

You should avoid using global where possible.

Read the tutorial by Rob to understand why.

http://coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

Have fun!

burhan