How do you make a physics draggable object “stick” to another physics object when dragged?
[import]uid: 9046 topic_id: 4476 reply_id: 304476[/import]
This was asked somewhere else, but I can’t find the link.
If all you want is to force the ‘stuck’ object to move with the ‘stuck to’ object, then you could remove the physics object and recreate a new one around both. Not brilliant and a bit messy.
If you don’t mind a bit of looseness in the ‘sticky’ contact, then you could listen for a collision (ok, that’s somewhat obvious) then create a distance joint between the two at the moment of impact. You’d probably want to kill the collision listener or something, because they would fire like crazy and cause performance problems.
There’s probably a lot of flash samples out there which do this…
matt. [import]uid: 8271 topic_id: 4476 reply_id: 14114[/import]
Thanks Matt,
I’ve actually already tried all three of those methods. Removing the physics object is bad because unfortunately it kills the entire physics world when doing it - even pausing. Messy isn’t the word.
I do have a listener built on collision which is where I’m experimenting now. I’m listening for a collision event on the two objects, then trying to make joint where they collided. It’s the least messy of all.
[import]uid: 9046 topic_id: 4476 reply_id: 14117[/import]
Sorta up against a wall here.
When I process a collision event and try to create a joint it doesn’t work and I get this message in the console:
Assertion failed: (IsLocked() == false), function CreateJoint, file /Users/ansca/.hudson/jobs/Main-DMG/workspace/platform/mac/…/…/external/Box2D_v2.1.2/Box2D/Box2D/Dynamics/b2World.cpp, line 184.
/Applications/Corona.243/Corona Terminal: line 9: 18380 Abort trap “$path/Corona Simulator.app/Contents/MacOS/Corona Simulator” $*
Here is my code to add the joint -
local function onCollision( event )
MyJoint=physics.newJoint( “weld”, square, circle, event.x, event.y )
end
Runtime:addEventListener( “collision”, onCollision )
Anyone got anything to help?
[import]uid: 9046 topic_id: 4476 reply_id: 14123[/import]
Yes, I think this is because you’re trying to add a joint within a collision event handler. Set a timer to go off for as short a period as possible and just have it add the joint. Its odd, but it seems to be a bug that you can’t modify certain elements of objects when responding to certain physics events.
Let us know how it goes…
matt [import]uid: 8271 topic_id: 4476 reply_id: 14126[/import]
Matt,
Where would you add the timer event? Inside the collision listener? [import]uid: 9046 topic_id: 4476 reply_id: 14127[/import]
it seems related to the issues mentioned in this thread:
The lesson learnt is not to mess with the physics properties inside of the collision event handler and defer it to a handler that hasn’t locked up the physics world, like enterFrame or a timer.
Hopefully Ansca gets around to either fix this or to provide us with some best-practices docs of what and what not to do in collision handlers.
-Frank.
[import]uid: 8093 topic_id: 4476 reply_id: 14135[/import]
@MBD Yes, in the collision handler. @FramkS has the right post, just above. Basically, I believe the problem comes from the physics object being in a locked state for various, perfectly logical, reasons.
M [import]uid: 8271 topic_id: 4476 reply_id: 14250[/import]
Do you guys have an example of how you might go about it? (albeit a working example)
I’m still stuck on this tiny little issue but as with all tiny little issues they are a deal breaker for my entire app.
[import]uid: 9046 topic_id: 4476 reply_id: 14381[/import]
There is another thread at the moment which indicates that the “don’t modify Box2D objects within their own handlers” rule is part of the Box2D system and not a bug. It actually sounds reasonable to me for reasons I can’t quite put my finger on, but have run up against in the past.
Anyway, just fire a 1 time timer from within the collision handler and get it to call a function which will perform the modification you want. Obviously, if you need it to not fire any collisions before the timer gets polled, just have a value set on your table which indicates to your table’s functions that they should not do anything.
matt. [import]uid: 8271 topic_id: 4476 reply_id: 14388[/import]
What do you mean by “stick” to another object? What is the game situation you are dealing with here? I’m having trouble understanding what you are trying to do. [import]uid: 12108 topic_id: 4476 reply_id: 14408[/import]
Sure,
Imagine gameplay where a person walks by and you throw cactus’s at them, or perhaps you are throwing stickers at a static window.
Synopsis
Two objects - both are
psychics objects.
A collision detection listener on one object.
When collision is detected, fire an event where objecta creates a physics joint on objectb where it touched it at (event.y, event.x) or the like.
[import]uid: 9046 topic_id: 4476 reply_id: 14409[/import]
ah okay that “cacti stuck to a person” example makes sense. Now I’m intrigued by this idea, I’ll probably try to figure this out later. [import]uid: 12108 topic_id: 4476 reply_id: 14413[/import]
I can think of a ton of ways this function would be useful and I’m surprised it’s not a part of the physics body engine.
If anyone comes up with a working example I’d appreciate it!
Meanwhile I’ll keep plugging away as well -
[import]uid: 9046 topic_id: 4476 reply_id: 14415[/import]
I’ve been thinking about this problem and although I don’t have a brilliant solution, as far as pure math solutions would go, I do have a Box2D oriented solution which I think will work well enough. Let me know what you think…
[lua]-- remove status bar
display.setStatusBar( display.HiddenStatusBar )
– start physics
local physics = require( “physics” )
physics.start()
physics.setGravity( 0, 0 )
physics.setDrawMode( “hybrid” ) – normal, hybrid, debug
– creates a wall to bounce things off
function addWall( x, y, width, height )
local wall = display.newRect( 0, 0, width, height )
– give it a name so we don’t try to add joints to it
wall.name = “wall”
wall:setFillColor( 255, 255, 255 )
physics.addBody( wall, “static”, { friction=1, bounce=.5, density=1 } )
wall.x, wall.y = x, y
end
– create the walls round the edge of the screen
addWall( display.contentWidth/2, 0, display.contentWidth, 10 )
addWall( display.contentWidth, display.contentHeight/2, 10, display.contentHeight )
addWall( display.contentWidth/2, display.contentHeight, display.contentWidth, 10 )
addWall( 0, display.contentHeight/2, 10, display.contentHeight )
– creates a ball with its ability to join to other balls
function addBall( event )
– add a ball when there is a tap on the background
if (event.numTaps == 1) then
– create a ball to bounce around
local radius = math.random( 10, 60 )
local ball = display.newCircle( event.x, event.y, radius )
ball.name = “ball”
ball.radius = radius
ball:setFillColor( math.random(150, 255), math.random(150, 255), math.random(150, 255) )
physics.addBody( ball, “dynamic”, { friction=1, bounce=.7, density=1, radius=radius } )
– touches on the ball will drag it round the screen
function ball:touch( event )
if (event.phase == “began”) then
– set drag focus to the ball to be dragged
display.getCurrentStage():setFocus( ball )
ball.joint = physics.newJoint( “touch”, ball, event.x, event.y )
elseif (event.phase == “moved”) then
– drag the ball
ball.joint:setTarget( event.x, event.y )
else
– stop dragging the ball
display.getCurrentStage():setFocus( nil )
ball.joint:removeSelf()
end
– tell system we’ve handled the touch
return true
end
– listen for touch drag on the ball
ball:addEventListener( “touch”, ball )
– used to attach the weld joint, because that can’t be done in the collision event handler
function ball:timer( event )
– only attach the joint to balls and weld is not already attached (use a table to add multiple joints)
if (ball.weld == nil and ball.other ~= nil) then
– add joint
ball.weld = physics.newJoint( “weld”, ball, ball.other, ball.x, ball.y )
– we don’t need to keep track of the other object to be jointed
ball.other = nil
end
end
– when collisions happen start the timer to add the joint because it can’t be done here
function ball:collision( event )
– only attach the joint to balls, not walls!
if (event.other.name == “ball”) then
– keep track of the other object to join to
ball.other = event.other
– start the timer on a very short expiry
timer.performWithDelay( 0, ball, 1 )
end
end
– listen for collisions with the ball
ball:addEventListener( “collision”, ball )
end
– tell system we’ve handled the tap
return true
end
– watch the background for taps to create new balls
Runtime:addEventListener( “tap”, addBall )[/lua] [import]uid: 8271 topic_id: 4476 reply_id: 14487[/import]
@horacebury
Great example, Carlos had pointed out a few things yesterday along the same lines as you’ve demonstrated here. Thanks!
How would you go about sticking the balls to a wall?
[import]uid: 9046 topic_id: 4476 reply_id: 14502[/import]
Scratch that, I just found it.
Just replacing the line =
if (event.other.name == “ball”) then
with
if (event.other.name == “wall”) then
did the trick.
Thanks again -
[import]uid: 9046 topic_id: 4476 reply_id: 14504[/import]
cool demo, thanks for the code [import]uid: 12108 topic_id: 4476 reply_id: 14513[/import]
Just thought I would make it known that this is available as a downloadable main.lua (zipped):
https://files.me.com/horacebury/7h7wrf
matt [import]uid: 8271 topic_id: 4476 reply_id: 14516[/import]
horacebury, will you contact me offline at our contact form located at http://MoonbeamDevelopment.com.
Thanks!
[import]uid: 9046 topic_id: 4476 reply_id: 14527[/import]