Snappy magnetism

You know how when a product is well made, if magnets are involved there is a certain snap to them. Like with the Apple Watch charger or AirPods seat in the case. It’s almost as if there’s no pull until they’re close, and then it’s a good, strong click, but pulling away again is smooth and fluid.

I’ve been trying to model this with Corona. Having been through many iterations I’ve found that a good magnetic click can be performed with a simple touch joint being engaged at the right time. Almost no modifications are needed to the default joint values.

Where the problem begins is when the object being magnetised starts to be built up with other physical attributes. For example, other bodies connected by pivot or weld joints. In particular, I get a nice, snappy magnet effect until I add a shadow body joined by a weld; Then the combined mass generates too much inertia and the effect is lost when the bodies wobble around the touch target.

My good magnet sample is below, but my question is how to keep the effect while applying it to more complex objects?

local physics = require("physics") physics.start() physics.setGravity(0,0) physics.setDrawMode("hybrid") local function touch(e) if (e.phase == "began") then e.target.hasFocus = true display.currentStage:setFocus(e.target) e.target.touchjoint = physics.newJoint( "touch", e.target, e.x, e.y ) return true elseif (e.target.hasFocus) then e.target.touchjoint:setTarget( e.x, e.y ) if (e.phase == "moved") then else e.target.hasFocus = nil display.currentStage:setFocus(nil) e.target.touchjoint:removeSelf() e.target.touchjoint = nil end return true end return false end local function newconnector( base, x, y, r ) x, y = base:localToContent( x, y ) local dot = display.newGroup() dot.x, dot.y = x, y physics.addBody( dot, "dynamic", { isSensor=true, radius=r, filter={ categoryBits=1, maskBits=2 } } ) physics.newJoint( "weld", base, dot, dot.x, dot.y ) local joint local function moveTo( target, connector, dot ) timer.performWithDelay( 350, function() joint = physics.newJoint( "touch", target, connector.x, connector.y ) joint:setTarget( dot.x, dot.y ) end, 1 ) end function dot:collision(e) if (e.phase == "began") then if (not joint) then moveTo( base, dot, e.other ) end else if (joint) then joint:removeSelf() joint = nil end end return true end dot:addEventListener( "collision" ) return dot end local function newbar( x, y ) local rect = display.newRoundedRect( x,y , 233,100 , 25 ) physics.addBody( rect, "dynamic", { isSensor=true, density=0, friction=.1, bounce=.1 } ) rect.linearDamping = 2 rect.angularDamping = 2 rect:addEventListener( "touch", touch ) newconnector( rect, -75, 0, 25 ) newconnector( rect, 75, 0, 25 ) return rect end local function newdot( x, y, r ) local dot = display.newGroup() dot.x, dot.y = x, y physics.addBody( dot, "dynamic", { isSensor=true, radius=r, filter={ categoryBits=2, maskBits=1 } } ) return dot end newbar( 200, 200 ) newdot( 233-75, 500, 25 ) newdot( 233+75, 500, 25 )

suggest you try adding up the combined mass of your welded bodies to vary the touch joint’s force.  a touch joint’s default force is calc’d from the mass of the one body it’s attached to, it won’t know about the mass of other bodies that might be welded to it, so it’ll be too weak by default for their combined mass (as you’ve described).

Yep. That was my thought, too. Tried it and went well beyond that value. It was fairly easy to calculate as it’s simply the body + a duplicate body representing the shadow.

Thanks for that great idea horace!  I was coming here with a snapping physics objects problem and your idea to use touch joints is perfect.

Not sure if you ever figured out your problem, but I’m using your moveTo() fn on a multi-segemented rope body and I too have the wobble issue.

I’m going to try to replace the touch joint with a pivot once the snap is complete to see if that fixes the issue - fairly confident that will do it.

https://gyazo.com/7ebcdf6cba1c5f8b86f4be4eea696429

After playing around with it for a bit, looks like the problem has something to do with the mass of your “dot”. 

For instance, increasing the radius of the dot to 5 and density to 1 will control the wobble.  Further increasing radius to 10 will almost remove wobble entirely, which is the setting I’m using in the screen below:

https://gyazo.com/1064522b7383eb8afbfbecc9fffc2df6

dotPhysics = {radius = 10, isSensor = true, density = 1}

Funnily enough I did solve my particular problem. I simply used a much higher strength of joint, then checked the distance of the touch being used to drag magnetised objects away and dropped the joint strength beyond a given distance/threshold.

suggest you try adding up the combined mass of your welded bodies to vary the touch joint’s force.  a touch joint’s default force is calc’d from the mass of the one body it’s attached to, it won’t know about the mass of other bodies that might be welded to it, so it’ll be too weak by default for their combined mass (as you’ve described).

Yep. That was my thought, too. Tried it and went well beyond that value. It was fairly easy to calculate as it’s simply the body + a duplicate body representing the shadow.

Thanks for that great idea horace!  I was coming here with a snapping physics objects problem and your idea to use touch joints is perfect.

Not sure if you ever figured out your problem, but I’m using your moveTo() fn on a multi-segemented rope body and I too have the wobble issue.

I’m going to try to replace the touch joint with a pivot once the snap is complete to see if that fixes the issue - fairly confident that will do it.

https://gyazo.com/7ebcdf6cba1c5f8b86f4be4eea696429

After playing around with it for a bit, looks like the problem has something to do with the mass of your “dot”. 

For instance, increasing the radius of the dot to 5 and density to 1 will control the wobble.  Further increasing radius to 10 will almost remove wobble entirely, which is the setting I’m using in the screen below:

https://gyazo.com/1064522b7383eb8afbfbecc9fffc2df6

dotPhysics = {radius = 10, isSensor = true, density = 1}

Funnily enough I did solve my particular problem. I simply used a much higher strength of joint, then checked the distance of the touch being used to drag magnetised objects away and dropped the joint strength beyond a given distance/threshold.