Collision occuring before an actual collision

Hi there,

I have a little problem with “jumping” onto a platform and determining if the player hits the side or lands on top of the platform. When I do a basic position test, checking the x pos of the player and the platform, the collision event is firing early, which means that the player hasn’t even collided yet with the platform even though it fires the event. The collision is fired between 2 to 5 pixels early.

I have created a demo, when you click the background a linear pulse is applied to a box (which represents the player). I would like it make something happen when the player successfully lands on the platform (rather than hits the side), but I cannot achieve this because when I check the x positions the player’s (box) right hand side is still left of the platform.

I am struggling to explain exactly what I mean, but the following code illustrates the problem:

-- include Corona's "physics" library local physics = require "physics" physics.setScale(80) physics.start() physics.setDrawMode( "hybrid" ) local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 local box local background local hasTouched = false -- display a background image background = display.newRect(0,0, display.contentWidth, display.contentHeight ) background.anchorX = 0 background.anchorY = 0 background:setFillColor(1,1,1) -- make a box and position it box = display.newRect( 150, 800, 78, 74 ) box.anchorX = 0 box.anchorY = 0 box:setFillColor(182/255, 243/255, 226/255) -- add physics to the box physics.addBody( box, { density=1.0, friction=1, bounce=0 } ) box.objectName = "box" box.isFixedRotation = true -- create a floor object and add physics local floor = display.newRect( 0 , display.contentHeight, screenW, 82 ) floor.anchorX = 0 floor.anchorY = 1 floor:setFillColor(122/255, 207/255, 30/255) floor.objectName = "floor" physics.addBody( floor, "static", { friction=0.3 } ) -- create platform local platform = display.newRect(300, floor.y - floor.height - 200, 200, 10) platform.anchorX = 0 platform.anchorY = 0 platform:setFillColor(86/255, 115/255, 207/255) platform.objectName = "platform" physics.addBody( platform, "static", { density=1.0, friction=1000, bounce=0 } ) function onCollision( event ) &nbsp;&nbsp;&nbsp; if ( event.phase == "began" ) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local boxRightX = event.target.x + event.target.width &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local platformLeftX = event.other.x &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local boxTopY = event.target.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local platformTopY = event.other.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- check that box is not hitting the side or underneath of the platform &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- but the problem is, is that this fires even when we don't hit the side &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if boxRightX \< platformLeftX or boxTopY \> platformTopY then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine = display.newLine( boxRightX , 0, boxRightX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine:setStrokeColor( 0, 0, 1 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine = display.newLine( platformLeftX ,0, platformLeftX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine:setStrokeColor( 1, 0, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxRightX: " .. boxRightX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformLeftX: " .. platformLeftX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxTopY: " .. boxTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformTopY: " .. platformTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "box hit side and should fall, but is infact sitting on the platform") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; elseif ( event.phase == "ended") then &nbsp;&nbsp;&nbsp; end end function onTap() &nbsp;&nbsp;&nbsp; if not hasTouched then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; box:applyLinearImpulse(1.2, -9.8, box.x + box.width/2, box.y + box.height/2 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasTouched = true &nbsp;&nbsp;&nbsp; end end physics.start() physics.setGravity( 0, 20 ) background:addEventListener( "tap", onTap ) box:addEventListener( "collision", onCollision )

I hope that makes sense,

Many thanks for your help,

Mike

 

You should try switching the collision phase from “began” to “ended” and see if it gives you the behavior you’re looking for.

Unfortunately, because the box is sitting on top of the platform it still remains in contact with it, therefore the “ended” phase of a collision is not fired until you move off the platform.

I have modified the code so that rather than checking inside the onCollision function, I call it 10 milliseconds later allowing the game engine a bit of time to calculate the new position of the box. This appears to work, but I wonder if this might introduce some issues that I cannot foresee?

-- include Coronas "physics" library local physics = require "physics" physics.setScale(80) physics.start() physics.setDrawMode( "hybrid" ) local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 local box local background local hasTouched = false -- display a background image background = display.newRect(0,0, display.contentWidth, display.contentHeight ) background.anchorX = 0 background.anchorY = 0 background:setFillColor(1,1,1) -- make a box and position it box = display.newRect( 150, 800, 78, 74 ) box.anchorX = 0 box.anchorY = 0 box:setFillColor(182/255, 243/255, 226/255) -- add physics to the box physics.addBody( box, { density=1.0, friction=1, bounce=0 } ) box.objectName = "box" box.isFixedRotation = true -- create a floor object and add physics local floor = display.newRect( 0 , display.contentHeight, screenW, 82 ) floor.anchorX = 0 floor.anchorY = 1 floor:setFillColor(122/255, 207/255, 30/255) floor.objectName = "floor" physics.addBody( floor, "static", { friction=0.3 } ) -- create platform local platform = display.newRect(300, floor.y - floor.height - 200, 200, 10) platform.anchorX = 0 platform.anchorY = 0 platform:setFillColor(86/255, 115/255, 207/255) platform.objectName = "platform" physics.addBody( platform, "static", { density=1.0, friction=1000, bounce=0 } ) function onCollision( event ) &nbsp;&nbsp;&nbsp; if ( event.phase == "began" ) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if event.other.objectName == "platform" then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local eventClosure = function() checkWithDelay(event) end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.performWithDelay(10, eventClosure) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; elseif ( event.phase == "ended") then &nbsp;&nbsp;&nbsp; end end function checkWithDelay( event ) &nbsp;&nbsp;&nbsp; local boxRightX = event.target.x + event.target.width &nbsp;&nbsp;&nbsp; local platformLeftX = event.other.x &nbsp;&nbsp;&nbsp; local boxTopY = event.target.y &nbsp;&nbsp;&nbsp; local platformTopY = event.other.y &nbsp;&nbsp;&nbsp; -- check that box is not hitting the side or underneath of the platform &nbsp;&nbsp;&nbsp; -- but the problem is, is that this fires even when we dont hit the side &nbsp;&nbsp;&nbsp; if boxRightX \< platformLeftX or boxTopY \> platformTopY then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine = display.newLine( boxRightX , 0, boxRightX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine:setStrokeColor( 0, 0, 1 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine = display.newLine( platformLeftX ,0, platformLeftX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine:setStrokeColor( 1, 0, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine = display.newLine( 0 , boxTopY, screenW, boxTopY ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine:setStrokeColor( 0, 1, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxRightX: " .. boxRightX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformLeftX: " .. platformLeftX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxTopY: " .. boxTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformTopY: " .. platformTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "box hit side and should fall, but is infact sitting on the platform") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; print("box landed on top of the platform") end function onTap() &nbsp;&nbsp;&nbsp; if not hasTouched then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; box:applyLinearImpulse(1.2, -9.8, box.x + box.width/2, box.y + box.height/2 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasTouched = true &nbsp;&nbsp;&nbsp; end end physics.start() physics.setGravity( 0, 20 ) background:addEventListener( "tap", onTap ) box:addEventListener( "collision", onCollision )

This solution didn’t work when it came to being implemented into the full game.

Rather than detect the X pos, I am now detecting the x and y linear velocity is 0, and the (box.y + box.height) is less than the y of the platform. As the box stops totally when it hits the platform this approach works - at least for now.

Assuming things always gets me into trouble, so I’ll point you to this tutorial on Jumping logic that was written a while ago. I’m not going to assume you’ve seen it:

http://coronalabs.com/blog/2013/02/19/more-physics-tricks-explained/

I will say that, when it comes to jumping logic, starting out simple and then adding in the harder parts is always key. Also, I always find that having timers set within Collision functions creates more problems than solutions, but that could just be me.

Good luck!

You should try switching the collision phase from “began” to “ended” and see if it gives you the behavior you’re looking for.

Unfortunately, because the box is sitting on top of the platform it still remains in contact with it, therefore the “ended” phase of a collision is not fired until you move off the platform.

I have modified the code so that rather than checking inside the onCollision function, I call it 10 milliseconds later allowing the game engine a bit of time to calculate the new position of the box. This appears to work, but I wonder if this might introduce some issues that I cannot foresee?

-- include Coronas "physics" library local physics = require "physics" physics.setScale(80) physics.start() physics.setDrawMode( "hybrid" ) local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth\*0.5 local box local background local hasTouched = false -- display a background image background = display.newRect(0,0, display.contentWidth, display.contentHeight ) background.anchorX = 0 background.anchorY = 0 background:setFillColor(1,1,1) -- make a box and position it box = display.newRect( 150, 800, 78, 74 ) box.anchorX = 0 box.anchorY = 0 box:setFillColor(182/255, 243/255, 226/255) -- add physics to the box physics.addBody( box, { density=1.0, friction=1, bounce=0 } ) box.objectName = "box" box.isFixedRotation = true -- create a floor object and add physics local floor = display.newRect( 0 , display.contentHeight, screenW, 82 ) floor.anchorX = 0 floor.anchorY = 1 floor:setFillColor(122/255, 207/255, 30/255) floor.objectName = "floor" physics.addBody( floor, "static", { friction=0.3 } ) -- create platform local platform = display.newRect(300, floor.y - floor.height - 200, 200, 10) platform.anchorX = 0 platform.anchorY = 0 platform:setFillColor(86/255, 115/255, 207/255) platform.objectName = "platform" physics.addBody( platform, "static", { density=1.0, friction=1000, bounce=0 } ) function onCollision( event ) &nbsp;&nbsp;&nbsp; if ( event.phase == "began" ) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if event.other.objectName == "platform" then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; local eventClosure = function() checkWithDelay(event) end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.performWithDelay(10, eventClosure) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; elseif ( event.phase == "ended") then &nbsp;&nbsp;&nbsp; end end function checkWithDelay( event ) &nbsp;&nbsp;&nbsp; local boxRightX = event.target.x + event.target.width &nbsp;&nbsp;&nbsp; local platformLeftX = event.other.x &nbsp;&nbsp;&nbsp; local boxTopY = event.target.y &nbsp;&nbsp;&nbsp; local platformTopY = event.other.y &nbsp;&nbsp;&nbsp; -- check that box is not hitting the side or underneath of the platform &nbsp;&nbsp;&nbsp; -- but the problem is, is that this fires even when we dont hit the side &nbsp;&nbsp;&nbsp; if boxRightX \< platformLeftX or boxTopY \> platformTopY then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine = display.newLine( boxRightX , 0, boxRightX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine:setStrokeColor( 0, 0, 1 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; blueLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine = display.newLine( platformLeftX ,0, platformLeftX, screenH ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine:setStrokeColor( 1, 0, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine = display.newLine( 0 , boxTopY, screenW, boxTopY ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine:setStrokeColor( 0, 1, 0 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; greenLine.strokeWidth = 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxRightX: " .. boxRightX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformLeftX: " .. platformLeftX) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("boxTopY: " .. boxTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print("platformTopY: " .. platformTopY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print( "box hit side and should fall, but is infact sitting on the platform") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; print("box landed on top of the platform") end function onTap() &nbsp;&nbsp;&nbsp; if not hasTouched then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; box:applyLinearImpulse(1.2, -9.8, box.x + box.width/2, box.y + box.height/2 ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasTouched = true &nbsp;&nbsp;&nbsp; end end physics.start() physics.setGravity( 0, 20 ) background:addEventListener( "tap", onTap ) box:addEventListener( "collision", onCollision )

This solution didn’t work when it came to being implemented into the full game.

Rather than detect the X pos, I am now detecting the x and y linear velocity is 0, and the (box.y + box.height) is less than the y of the platform. As the box stops totally when it hits the platform this approach works - at least for now.

Assuming things always gets me into trouble, so I’ll point you to this tutorial on Jumping logic that was written a while ago. I’m not going to assume you’ve seen it:

http://coronalabs.com/blog/2013/02/19/more-physics-tricks-explained/

I will say that, when it comes to jumping logic, starting out simple and then adding in the harder parts is always key. Also, I always find that having timers set within Collision functions creates more problems than solutions, but that could just be me.

Good luck!