In this tutorial we will try to simulate magnets in Box2d world. As usually we will use Dragging example as a start for our project.

So first thing is to create a table where we will store all our magnet objects. So let's add this line inside init method:

--create table to store magnets
self.magnets = {}

Then we will create magnet representing objects. It's nothing new really, pretty similar to how we create ball object, only now magnets will be static and have 2 new properties: strength of magnet and radius of magnetic field.

--this method will create magnet objects
function scene:magnet(x, y, strength, magnetRadius)
	--create magnet bitmap object from magnet graphic
	local magnet = Bitmap.new(Texture.new("./magnet.png"))
	--reference center of the magnet for positioning
	magnet:setAnchorPoint(0.5,0.5)
	
	magnet:setPosition(x,y)
	
	--get radius
	local radius = magnet:getWidth()/2
	
	--create box2d physical object
	local body = self.world:createBody{type = b2.STATIC_BODY}
	body:setPosition(magnet:getX(), magnet:getY())
	body:setAngle(magnet:getRotation() * math.pi/180)
	local circle = b2.CircleShape.new(0, 0, radius)
	local fixture = body:createFixture{shape = circle, density = 1.0, 
	friction = 0.6, restitution = 0.8}
	magnet.body = body
	magnet.body.type = "ball"
	
	--set two new properties
	--radius of magnetic field
	magnet.radius = magnetRadius
	--strength of magnet
	magnet.strength = strength
	
	--add to scene
	self:addChild(magnet)
	
	--add magnet to mangnets table
	self.magnets[#self.magnets+1] = magnet
	
	--return created object
	return magnet
end

Now we can create magnet objects inside init function, you'll see they appear on screen, but thet still won't do anything.

--create magnets (x, y, strength, radius)
self:magnet(200, 250, 500, 200)
self:magnet(600, 250, 500, 200)

To make them attract the ball, we will apply linear impulse to the ball in the direction of the magnets in each onEnterFrame event, if ball is inside a magnetic field radius. So just add this snippet into your onEnterFrame method:

--now we iterate through all magnets
for i, val in pairs(self.magnets) do
	--calculate vectors
	local xDiff = val:getX() - self.ball:getX()
	local yDiff = val:getY() - self.ball:getY()
	local rad2 = xDiff*xDiff + yDiff*yDiff;
	local distance = math.sqrt(rad2)
	--and if it is smaller than magnet radius
	if distance <= val.radius then
		--apply impulse towards magnet
		self.ball.body:applyLinearImpulse((val.strength*xDiff)/rad2, 
			(val.strength*yDiff)/rad2, self.ball:getX(), self.ball:getY())
	end
end

And that's it. No here's a video example of how it actually works. Don't forget that you can change the strength and radius of magnetic field.

And here's a Gideros project example for you to play. ;)