Setting gravity multiple times fails

This short snippet should set the gravity to a regular (0,10), then set it to (0,0), create and object and finally set gravity back to the original (0,10)

You would expect the object created to begin dropping, as it has density, is not fixed in position in any way and the gravity is set to pull downwards - except it doesn’t. It will begin dropping, however, if the gravity does not change before (and after) the object is created.

Bug?

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") timer.performWithDelay( 1000, function()     print("gravity off")     physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function()     local c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 )     physics.addBody( c, "dynamic", {radius=100} ) end, 1 ) timer.performWithDelay( 3000, function()     print("gravity on")     physics.setGravity(0,10) end, 1 )  

ok, well, here’s a little thing which makes it work - setting the linear velocity of the body to a very small value seems to remind the physics engine that the body is there and thus apply gravity again:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("linear velocity") c:setLinearVelocity(0,-0.000000001) -- very slight nudge up c:setLinearVelocity(0,0) end, 1 )

I suspect this is because “gravity” appears to forget about objects if they go to sleep, though that can be fixed by forcing them to be awake:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) c.isSleepingAllowed = false -- don't let gravity forget about the body end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 )

However, this is not a particularly good solution because the body will continue to consume CPU time.

Ok, fortunately, there is a more elegant solution to both of these: wake the body up temporarily when shifting the gravity from (0,0) to (0,10):

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("no sleeping") c.isSleepingAllowed = false c.isSleepingAllowed = true end, 1 )

I like this because it doesn’t risk affecting the body’s velocity or keeping the body awake. It is, in effect, a little reminder to Box2D to start applying gravity again. I’m not sure if this is Box2D or just a bug, though I can live with it for now.

I will remind each object that they should wake up by dispatching an event:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") local function wakeUp( self, event ) print( self, event ) self.isSleepingAllowed = false self.isSleepingAllowed = true return false end print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) c.wakeUp = wakeUp Runtime:addEventListener( "wakeUp", c ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("no sleeping") Runtime:dispatchEvent{ name="wakeUp" } end, 1 )

ok, well, here’s a little thing which makes it work - setting the linear velocity of the body to a very small value seems to remind the physics engine that the body is there and thus apply gravity again:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("linear velocity") c:setLinearVelocity(0,-0.000000001) -- very slight nudge up c:setLinearVelocity(0,0) end, 1 )

I suspect this is because “gravity” appears to forget about objects if they go to sleep, though that can be fixed by forcing them to be awake:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) c.isSleepingAllowed = false -- don't let gravity forget about the body end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 )

However, this is not a particularly good solution because the body will continue to consume CPU time.

Ok, fortunately, there is a more elegant solution to both of these: wake the body up temporarily when shifting the gravity from (0,0) to (0,10):

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("no sleeping") c.isSleepingAllowed = false c.isSleepingAllowed = true end, 1 )

I like this because it doesn’t risk affecting the body’s velocity or keeping the body awake. It is, in effect, a little reminder to Box2D to start applying gravity again. I’m not sure if this is Box2D or just a bug, though I can live with it for now.

I will remind each object that they should wake up by dispatching an event:

require("physics") physics.start() physics.setGravity(0,10) physics.setDrawMode("hybrid") local function wakeUp( self, event ) print( self, event ) self.isSleepingAllowed = false self.isSleepingAllowed = true return false end print("gravity on") local c = nil timer.performWithDelay( 1000, function() print("gravity off") physics.setGravity(0,0) end, 1 ) timer.performWithDelay( 2000, function() print("new body") c = display.newCircle( display.contentCenterX, display.contentCenterY, 100 ) physics.addBody( c, "dynamic", {radius=100} ) c.wakeUp = wakeUp Runtime:addEventListener( "wakeUp", c ) end, 1 ) timer.performWithDelay( 3000, function() print("gravity on") physics.setGravity(0,10) end, 1 ) timer.performWithDelay( 4000, function() print("no sleeping") Runtime:dispatchEvent{ name="wakeUp" } end, 1 )