Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Restarting Level mechanism not working
Started by marek.skreko Mar 18 2020 12:12 PM

7 replies to this topic
lua corona beginner

Best Answer sporkfin , 19 March 2020 - 06:41 AM

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

 

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
 

 

 

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.
 


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

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

marek.skreko

[GLOBAL: userInfoPane.html]
marek.skreko
  • Observer

  • 4 posts
  • Corona SDK

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.  



[TOPIC: post.html]
#2

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 809 posts
  • Corona SDK

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.



[TOPIC: post.html]
#3

marek.skreko

[GLOBAL: userInfoPane.html]
marek.skreko
  • Observer

  • 4 posts
  • Corona SDK

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.



[TOPIC: post.html]
#4

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 809 posts
  • Corona SDK

  Best Answer

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

 

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
 

 

 

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.
 


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



[TOPIC: post.html]
#5

marek.skreko

[GLOBAL: userInfoPane.html]
marek.skreko
  • Observer

  • 4 posts
  • Corona SDK

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!



[TOPIC: post.html]
#6

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 809 posts
  • Corona SDK

@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!



[TOPIC: post.html]
#7

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 809 posts
  • Corona SDK

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!



[TOPIC: post.html]
#8

marek.skreko

[GLOBAL: userInfoPane.html]
marek.skreko
  • Observer

  • 4 posts
  • Corona SDK

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




[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: lua, corona, beginner