So, I’ve been working on this game where you drag objects onto a playing area which is populated with arbitrarily shaped objects (defined as complex bodies) and I wanted to implement a way of checking whether the dragged object was overlapping an object on the stage or not. In real time.
Turned out this wasn’t that easy… but I came up with a “hack” that did the job. Not very optimized or anything and I really hope there is a better way of doing it, but I’m sticking with it 'til I (or you) come up with something better. Hope it helps/inspires someone else with a similar problem.
This code assumes that you have created a display object named draggableObject and added a touch event handler to it:
[lua]function draggableObject:touch( event )
local phase = event.phase
– Some setup code etc has been removed for clarity
if phase == “moved” then
– Updates position. startX and startY are set elsewhere
self.x = event.x - self.startX
self.y = event.y - self.startY
– Here we call the method that checks for overlaps
self:checkLegalPosition()
– isPositionLegal is set to true when the object is created
– As an example I set the fill color to green or red respectively to show if the
– object is in the clear or not. You can do whatever you like here of course.
if self.isPositionLegal then
self:setFillColor(0, 255, 0)
else
self:setFillColor(255,0,0)
end
– Drop when finger is lifted
elseif phase == “ended” or phase == “cancelled” then
– Some code removed for clarity
– Check if object is in the clear.
– If so drop it on the playing area. If not remove it.
– This is just what I did. You might want to do something else here.
if self.isPositionLegal then
self:dropOnStage()
else
self:destroy() – This also destroys the collision detector if it exists
end
end
return true
end[/lua]
Here’s the method that checks for a legal position. If this seems rather brute force, it’s because it is. I tried using phase.began and phase.ended in the collision event but the “ended” phase would fire even if the object was still overlapping other object. Thus I resorted to creating a temporary object, letting it listen for a collision event and then destroying it. Every time the phase.moved fired from the touch event.
[lua]function draggableObject:checkLegalPosition()
self.isPositionLegal = true
– This is the “hack”. It creates a temporary physics object and attaches a
– collision event listener to it. If there is a collision, isPositionLegal is set to false.
if not collisionDetector then
createCollisionDetector( self )
else
destroyCollisionDetector( self )
createCollisionDetector( self )
end
end[/lua]
These are the functions that creates the temporary detector object:
[lua]function createCollisionDetector( forObject )
– The following lines are quite specific to my game but I hope you get the gist of it
collisionDetector = display.newCircle( 0, 0, 16 )
registry.currentLevelStage:insert( collisionDetector )
collisionDetector.x, collisionDetector.y = registry.currentLevelStage:contentToLocal( forObject.x, forObject.y )
– These are the important lines
physics.addBody( collisionDetector, “static”, { isSensor = true, radius = 16 })
collisionDetector:addEventListener(“collision”, forObject)
end
– This should be pretty self-explanatory
function destroyCollisionDetector( forObject )
if collisionDetector then
collisionDetector:removeEventListener(“collision”, forObject)
collisionDetector:removeSelf()
collisionDetector = nil
end
end[/lua]
And this is the actual collision event handler:
[lua]function draggableObject:collision( event )
if event.phase == “began” then
self.isPositionLegal = false;
self:setFillColor(255, 0, 0)
end
return true
end[/lua]
Hope this makes some sense to you
And if you come up with a better solution, please let me know! I saw that the Ansca staff was working on a (maybe) related issue according to the roadmap: “Physics: simplified collision detection for “non-physical” cases”.
Cheers
/Daniel [import]uid: 45930 topic_id: 9488 reply_id: 309488[/import]
