physics.stop() cannot be called when the world is locked and in the middle of number crunching, such as during a collision event

I’m developing a Pong game, just to learn Solard2D.

When the ball touches an invisible segment all over the right or left edge of the screen then I have a point.

So on ball collision OnEvent I have the choice whether or not I have reached the required score, in this case I stop the physical world, the ball, and close the game.

I read that in on event I can’t close the physical world so I set a timer.

The problem is, in any case, I can’t stop the world. Where am I wrong?

Here are the pieces of code:

local function onCollision( self, event )
    if ( event.phase == "began" ) then
    if (self.Name == "ball") and (event.other.Name == "edgeDx" ) then
        if settingsTable["sound"] == true then audio.play(pointSnd) end
        writeScreenPoint()
        timer.performWithDelay( 25, stopBall, 1 )
        timer.performWithDelay( 30, centerBall, 1 )
        if someOneWins() == true then
           -- someone wins, I go on starting game screen
           composer.gotoScene( "welcome", { time=100, effect="crossFade" } )
        end
    end

   return true
end

function scene:hide( event )
   local phase = event.phase

   if ( phase == "will" ) then
      transition:pause()
      physics.pause()
 
      Runtime:removeEventListener(...)  -- remove all EventListener
  
      local result = function() return physicsStop( physics.stop() ) end
      repeat
         timer.performWithDelay( 25, result)
         print("Waiting physics stops...")
      until result == true

will never stops an loops forever.

Thanks!

Renato

I think you could create some flag in your collision function and then check this flag in the runtime.

timer.perforWithDelay() should work as well so something might be wrong with stopBall() or centerBall() probably.

Here’s code example maybe it’ll help:

local physics = require("physics")
physics.start()
physics.setDrawMode( "hybrid" )

local ball = display.newCircle(100, 100, 10)
ball.Name = "ball"
local lWall = display.newRect(0, 240, 10, 480)
local rWall = display.newRect(320, 240, 10, 480)
local uWall = display.newRect(160, 0, 320, 10)
local dWall = display.newRect(160, 480, 320, 10)
lWall.Name, rWall.Name, uWall.name, dWall.Name = "edgeDx", "edgeDx", "edgeDx", "edgeDx"

physics.addBody(ball, "dynamic", {radius = 10})
physics.addBody(lWall, "static")
physics.addBody(rWall, "static")
physics.addBody(uWall, "static")
physics.addBody(dWall, "static")

ball:applyForce( 0.2, 0.9, 0, 0 )

local function onCollision( self, event )
    if event.phase == "began" then
    	if self.Name == "ball" and event.other.Name == "edgeDx" then
    		ball.hasCollided = true

    		-- this also works
    		--[[
    			timer.performWithDelay( 30, function()
    				physics.stop()
    			end, 1)
    		--]]
    	end
    end
end
ball.collision = onCollision
ball:addEventListener( "collision" )

function onUpdate()
	if ball.hasCollided then
		physics.stop()
		Runtime:removeEventListener( "enterFrame", onUpdate )
	end
end
Runtime:addEventListener( "enterFrame", onUpdate )

This is happening because your composer.gotoScene() call will cause the current scene to hide before the onCollision() event has finished executing.

Using a flag is a good way of doing that or delay a call to a clean down function that will pause your game/world.

Thanks,

now works. But only if I close physics inside an eventListener.

If I call from eventListener a composer.gotoscene() without stop physics and I stop from a scene:hide i receive an error!

…and now going back on my “welcome” scene physics won’t start…
nightmare ;(

Renato