I have tried Brent’s suggestions one by one and only one of them solves the issue; namely creating objects in an inactive state and activate them only when I need them to start interacting. This also solves the issue that BeatsnBobs observed. Below is my new code: if you comment out every line where you see a isBodyActive statement and press the R button before the ball is shot up, then you can clearly see that the two balls skip in two different alternative positions (to the left and to the right) each time you press the button. I am not sure why that is, I can only report here something else that I have observed and might (or might not) be related: when a collision takes place, the x and y coordinates of the same static object are sometimes different by a few decimals (I am not going to reproduce that here as I would need to make one ball static, but I have observed the behaviour in a game of mine). So maybe (just a theory here) there is a small approximation issue in the engine (or it might even be Box2D) and it has something to do with where the objects are initially placed. Or maybe (second theory) a time lag between the time when corona instructs Box2D and when Box2D does results in Box2D computing a new position for active objects (I do not believe too much in this second theory because the positioning imprecision I observe does not go in the direction of the gravity)?
In any event, try and document this behaviour in the addBody APIs, that would be useful for people relying on dynamic and/or procedural generation of levels (i.e. reliant on automatically calculating precise positions of objects).
local physics = require("physics") -- \*\*\*\* NEW \*\*\*\* physics.start() -- \*\*\*\* NEW \*\*\*\* physics:setGravity(0, 30) -- \*\*\*\* NEW \*\*\*\* local widget = require("widget") local \_W = display.contentWidth local \_H = display.contentHeight local objects local mytimer local cleanUp local restart local start function cleanUp() timer.cancel(mytimer) mytimer = nil display.remove(objects) objects = nil end function restart() cleanUp() start() end function start() objects = display.newGroup() --local physics = require("physics") -- \*\*\*\* NEW \*\*\*\* --physics.start() -- \*\*\*\* NEW \*\*\*\* --physics:setGravity(0, 30) -- \*\*\*\* NEW \*\*\*\* --physics.pause() -- \*\*\*\* NEW \*\*\*\* local restartButton = widget.newButton{ id = "restart", width=200, height=200, label = "R", fontSize = 200, onRelease = restart, } restartButton:setReferencePoint( display.CenterReferencePoint ) restartButton.x = \_W - 105 restartButton.y = 105 local function drawBall(x, y) local ball = display.newCircle(x,y,25) local options = { bounce = 0.2, friction = 0.01, } physics.addBody(ball, "dynamic", options) return ball end -- Alternative button -- \*\*\*\* NEW \*\*\*\* local button=display.newRect(100,100,100,100) -- \*\*\*\* NEW \*\*\*\* objects:insert(button) -- \*\*\*\* NEW \*\*\*\* button:addEventListener("touch",restart) -- \*\*\*\* NEW \*\*\*\* local ball1 = drawBall(\_W/2 + 24, \_H - 50) ball1.isBodyActive = false -- \*\*\*\* NEW \*\*\*\* local ball2 = drawBall(\_W/2, \_H - 300) ball2.gravityScale = 0 ball2.isBodyActive = false -- \*\*\*\* NEW \*\*\*\* objects:insert(ball1) objects:insert(ball2) local function shoot() --physics.start() ball1.isBodyActive = true -- \*\*\*\* NEW \*\*\*\* ball2.isBodyActive = true -- \*\*\*\* NEW \*\*\*\* ball1:applyLinearImpulse(0,-100, 0, -25) end mytimer = timer.performWithDelay(1000, shoot) end start()