Restarting Level mechanism not working

Hello everyone, I am relatively new to Corona SDK, but so far I pretty enjoy working with this tool, however lately I’ve come across with a problem that for past several days I can’t seem to resolve.

I have problem with restarting level. At first I used to have gameScene and gameOverScene and after player has died the composer switched from gameScene to gameOverScene and from there clicking on replayButton it succesfully switched back to gameScene and game was restarted. However I decided to delete gameOverScene so after the player dies the pop up screen shows with replayButton still in the same scene. The screen/menu pops up, however replay button doesn’t work like it should. 

I tried to use composer with gotoScene() and similar functions, and go from current scene to current scene, unfrotunately no success. I decided to try to restart level manually - manually reset all the necessary variables and display objects. Unfortunately still no success.

There might be problem with the fact that I use multiple modules, because having functions in several files feels much more practical than to put everything into the file with scene. However if you know better way to part functions than modules, please let me know. It would be probably ideal if there is something like abstract methods or objects.

And now to the code:

in file level.lua

function scene:create( event ) -- Code here runs when the scene is first created but has not yet appeared on screen sceneGroup = self.view --[[local function enemyShoot( enemy ) local bullet = display.newRect( mainGroup, enemy.x-80, enemy.y, 20, 5) bullet.fill = {0,0,0} bullet.myName = "bullet" physics.addBody( bullet, "kinematic") bullet:setLinearVelocity( -400, 0) enemyTimer = timer.performWithDelay( 2000, function() enemyShoot( enemy ) end, 1 ) end]]-- physics.start() cre.createBackground() cre.createLevel1() cre.setGame(g) g.setPlayer(cre.createPlayer()) g.setComposer(composer) g.setCreator(cre) g.setBlocks(cre.getBlocksArray()) g.moving() Runtime:addEventListener( "collision", g.onCollision ) Runtime:addEventListener( "touch", g.playerEvent ) gameLoopTimer = timer.performWithDelay( 25, g.gameLoop, 0 ) sceneGroup:insert( cre.getBackGroup() ) sceneGroup:insert( cre.getMainGroup() ) sceneGroup:insert( cre.getPlayerGroup() ) sceneGroup:insert( cre.getFrontGroup() ) musicTrack = audio.loadStream( "s6.mp3") end

Functions in game.lua that may be related to the problem (function moving() is creating an error)

M.setBlocks = function( blocks ) blocksArray = blocks end M.destroyBlocks = function() for i in ipairs(blocksArray) do blocksArray[i]:removeSelf() end blocksArray = {} end M.moving = function() --this function creates an error for i in ipairs(blocksArray) do local vx,vy = blocksArray[i]:getLinearVelocity() blocksArray[i]:setLinearVelocity(vx-160, vy) end end M.stopping = function() for i in ipairs(blocksArray) do local vx,vy = blocksArray[i]:getLinearVelocity() if (blocksArray[i].myName ~= "blockMoving") then blocksArray[i]:setLinearVelocity( 0, 0) end end end M.death = function() --function that shows pop up menu after player dies dead = true M.stopping() local gameOver = display.newImageRect(mainGroup, "window.png", 550, 400) gameOver.x = display.contentCenterX gameOver.y = display.contentCenterY table.insert( elements, gameOver) local youLose = display.newImageRect(mainGroup, "Header.png", 235, 25) youLose.x = display.contentCenterX youLose.y = display.contentCenterY - 170 table.insert( elements, youLose) local score = display.newImageRect(mainGroup, "Score.png", 130, 20) score.x = display.contentCenterX - 150 score.y = display.contentCenterY - 90 table.insert( elements, score) local table1 = display.newImageRect(mainGroup, "Table.png", 220, 60) table1.x = display.contentCenterX + 65 table1.y = display.contentCenterY - 88 table.insert( elements, table1) local scoreValue = display.newText(mainGroup, 1485, display.contentCenterX + 65, display.contentCenterY - 92, "ethnocentric rg.ttf", 30) scoreValue:setTextColor( 0.9, 0.9, 0.9 ) table.insert( elements, scoreValue) local record = display.newImageRect(mainGroup, "Record.png", 130, 20) record.x = display.contentCenterX - 150 record.y = display.contentCenterY table.insert( elements, record) local table2 = display.newImageRect(mainGroup, "Table.png", 220, 60) table2.x = display.contentCenterX + 65 table2.y = display.contentCenterY + 2 table.insert( elements, table2) local recordValue = display.newText(mainGroup, 1485, display.contentCenterX + 65, display.contentCenterY - 2, "ethnocentric rg.ttf", 30) recordValue:setTextColor( 0.9, 0.9, 0.9 ) table.insert( elements, recordValue) local closeBtn = display.newImageRect(mainGroup, "Close\_BTN.png", 100, 100) closeBtn.x = display.contentCenterX - 140 closeBtn.y = display.contentCenterY + 120 table.insert( elements, closeBtn) local replayBtn = display.newImageRect(mainGroup, "Replay\_BTN.png", 100, 100) replayBtn.x = display.contentCenterX + 140 replayBtn.y = display.contentCenterY + 120 table.insert( elements, replayBtn) local function restartLevel() Runtime:removeEventListener( "tap", replayBtn ) M.destroyBlocks() c.createLevel1() M.setBlocks(c.getBlocksArray()) ply.y = display.contentWidth-400 for i in ipairs(elements) do display.remove(elements[i]) end dead = false M.moving() end replayBtn:addEventListener( "tap", restartLevel ) end

Some functions in creator.lua 

M.createBlock = function( x, y) local block = display.newImageRect(mainGroup, en.getBlock(), 32, 32 ) block.myName = "blockU" block.x = x block.y = y physics.addBody( block, "kinematic", {bounce = 0 } ) block.isSensor = true table.insert( blocksArray, block ) end M.createLevel1 = function() local top do top = 264 for i=1,20 do M.createBlockTop(i\*32 - 16, display.contentWidth-top) for j=1,7 do M.createBlock(i\*32 - 16, display.contentWidth-top + 32\*j) end end M.createBlockEndTop(654, display.contentWidth-top) M.createBlockEnd(654, display.contentWidth-top+32) M.createBush3(300,display.contentWidth-top-20) M.createFlower(500,display.contentWidth-top-20) end . . . end M.getBlocksArray = function() return blocksArray end

And now for the error 

game.lua:57: attempt to call method ‘getLinearVelocity’ (a nil value)

stack traceback: game.lua:57: in function ‘moving’

game.lua:133: in function ‘?’

?: in function <?:190>

From the message I concluded that blocksArray is nil, however I have no idea why, I know that I use function destroyBlocks() but then in restartLevel() function I set the blocksArray again.

Any tips? I am kinda lost.

Thank you for your time.  

Hello @marek,

If you can format your code so it is easier to read, that would be great.  You can use the <> button from the menu bar.

Looking at your error message, it looks like you tried to access the the linear velocity of something that wasn’t a physics object.  Since this happens when you restart a level, I think it is because you are trying to move a physics object but what you are really attempting to move is a display object that hasn’t been assigned physics properties yet.

After restart, try delaying physics calls until everything else is loaded.

Thank you sporkfin for your answer! I reformatted the code, hope it is better now.

I was thinking about what you said, but was unable to come up with solution. The thing is that in creator I create all those objects, like blocks, flowers, trees etc. and in create to each of these I assign physics body, in code provided above it is shown in function createBlock() in creator.lua. Then in restartLevel in game.lua I call function createLevel1 from creator.lua where I call those functions where I create the objects with physics body added. And then after that I call function moving(), but by then all objects should have existed again and have physics body added again.

Make sure everything has a name (object.myName)

In the M.moving( ) function - try printing the name of the object and its .isBodyActive state to double check that it is what you expect

[lua]

M.moving = function()

     for i in ipairs(blocksArray) do

          local obj = blocksArray[i]

          obj.myName = obj.myName or “unknown object”

          print(obj.myName, tostring( obj.isBodyActive ), obj.x, obj.y)

          local vx,vy = obj:getLinearVelocity()

          blocksArray[i]:setLinearVelocity(vx-160, vy) 

     end

end

[/lua]

You can also use the following function to do a long analysis of the objects - I can’t remember where I got this snippet but thanks to whoever game it to me.

[lua]

local function print_r ( t ) 

        local print_r_cache={}

        local function sub_print_r(t,indent)

                if (print_r_cache[tostring(t)]) then

                        print(indent…"*"…tostring(t))

                else

                        print_r_cache[tostring(t)]=true

                        if (type(t)==“table”) then

                                for pos,val in pairs(t) do

                                        if (type(val)==“table”) then

                                                print(indent…"["…pos…"] => “…tostring(t)…” {")

                                                sub_print_r(val,indent…string.rep(" ",string.len(pos)+8))

                                                print(indent…string.rep(" “,string.len(pos)+6)…”}")

                                        elseif (type(val)==“string”) then

                                                print(indent…"["…pos…’] => “’…val…’”’)

                                        else

                                                print(indent…"["…pos…"] => "…tostring(val))

                                        end

                                end

                        else

                                print(indent…tostring(t))

                        end

                end

        end

        if (type(t)==“table”) then

                print(tostring(t)…" {")

                sub_print_r(t,"  ")

                print("}")

        else

                sub_print_r(t,"  ")

        end

        print()

end

[/lua]

Thank you very much sporkfin!

I printed the objects as you said, the way you showed, and found out that the blocksArray still contained objects from previous game that I deleted, so they had no physics body. The thing is that I deleted all blocks by function destroyBlocks() only in game.lua, however I did not do the same in creator.lua so whenever I created blocks from creator, they were added on top of the deleted ones, and obviously you can’t move those objects with deleted body. 

I added function destroyBlocks to creator as well, and call it in restartLevel function and now it works! 

It is embarrasing that I spent so much time trying to figure this out, when in reality the mistake was so silly. 

I am sorry for taking your time, but you helped me a lot in finding where is the problem so thanks again!

@marek No apology needed, I’m happy to help out as many have helped me in the past.  We’ve all made the same errors before which gives us insights on where to look.  As you get better and better it will soon be you helping other people think through debugging process.  Keep up the good work!

Oh, and also remember to always delete all references to destroyed objects to they can be removed by the automatic garbage collection.  If not, they pop back up like phantoms and poison your code!

I appreciate your encouragement and will keep your advice in mind!

Hello @marek,

If you can format your code so it is easier to read, that would be great.  You can use the <> button from the menu bar.

Looking at your error message, it looks like you tried to access the the linear velocity of something that wasn’t a physics object.  Since this happens when you restart a level, I think it is because you are trying to move a physics object but what you are really attempting to move is a display object that hasn’t been assigned physics properties yet.

After restart, try delaying physics calls until everything else is loaded.

Thank you sporkfin for your answer! I reformatted the code, hope it is better now.

I was thinking about what you said, but was unable to come up with solution. The thing is that in creator I create all those objects, like blocks, flowers, trees etc. and in create to each of these I assign physics body, in code provided above it is shown in function createBlock() in creator.lua. Then in restartLevel in game.lua I call function createLevel1 from creator.lua where I call those functions where I create the objects with physics body added. And then after that I call function moving(), but by then all objects should have existed again and have physics body added again.

Make sure everything has a name (object.myName)

In the M.moving( ) function - try printing the name of the object and its .isBodyActive state to double check that it is what you expect

[lua]

M.moving = function()

     for i in ipairs(blocksArray) do

          local obj = blocksArray[i]

          obj.myName = obj.myName or “unknown object”

          print(obj.myName, tostring( obj.isBodyActive ), obj.x, obj.y)

          local vx,vy = obj:getLinearVelocity()

          blocksArray[i]:setLinearVelocity(vx-160, vy) 

     end

end

[/lua]

You can also use the following function to do a long analysis of the objects - I can’t remember where I got this snippet but thanks to whoever game it to me.

[lua]

local function print_r ( t ) 

        local print_r_cache={}

        local function sub_print_r(t,indent)

                if (print_r_cache[tostring(t)]) then

                        print(indent…"*"…tostring(t))

                else

                        print_r_cache[tostring(t)]=true

                        if (type(t)==“table”) then

                                for pos,val in pairs(t) do

                                        if (type(val)==“table”) then

                                                print(indent…"["…pos…"] => “…tostring(t)…” {")

                                                sub_print_r(val,indent…string.rep(" ",string.len(pos)+8))

                                                print(indent…string.rep(" “,string.len(pos)+6)…”}")

                                        elseif (type(val)==“string”) then

                                                print(indent…"["…pos…’] => “’…val…’”’)

                                        else

                                                print(indent…"["…pos…"] => "…tostring(val))

                                        end

                                end

                        else

                                print(indent…tostring(t))

                        end

                end

        end

        if (type(t)==“table”) then

                print(tostring(t)…" {")

                sub_print_r(t,"  ")

                print("}")

        else

                sub_print_r(t,"  ")

        end

        print()

end

[/lua]

Thank you very much sporkfin!

I printed the objects as you said, the way you showed, and found out that the blocksArray still contained objects from previous game that I deleted, so they had no physics body. The thing is that I deleted all blocks by function destroyBlocks() only in game.lua, however I did not do the same in creator.lua so whenever I created blocks from creator, they were added on top of the deleted ones, and obviously you can’t move those objects with deleted body. 

I added function destroyBlocks to creator as well, and call it in restartLevel function and now it works! 

It is embarrasing that I spent so much time trying to figure this out, when in reality the mistake was so silly. 

I am sorry for taking your time, but you helped me a lot in finding where is the problem so thanks again!

@marek No apology needed, I’m happy to help out as many have helped me in the past.  We’ve all made the same errors before which gives us insights on where to look.  As you get better and better it will soon be you helping other people think through debugging process.  Keep up the good work!

Oh, and also remember to always delete all references to destroyed objects to they can be removed by the automatic garbage collection.  If not, they pop back up like phantoms and poison your code!

I appreciate your encouragement and will keep your advice in mind!