Is it possible to get the force of a collision between two objects in Love2D/Box2D? If so, how?
You have access to the b2ContactImpulse in the PostSolve callback on the b2ContactListener. The normalImpulses field on b2ContactImpulse holds an impulse applied to both bodies in the direction of the contact normal.
An impulse is calculated as a change in velocity times the mass of the object, so the normalImpulses well describes how hard the two fixtures hit each other. Given the same relative velocity between two fixtures, the greater the sum of the masses of the fixtures, the greater the normalImpulses.
An impulse is equal to a force acting on an object over a period of time, so if you need to calculate the actual force, you can divide the impulse by the frame time you passed to the Step function and you should get a reasonable assessment of the actual force acting on the two objects, though since i don't understand the inner workings of Box2D, i don't know how accurate this assessment is. If you're just interested in gauging the force of impact, not in the strict physics sense, then using an impulse is just as effective.
World:setCallbacks( beginContact, endContact, preSolve, postSolve ) may solve your problem.
The postSolve function receive two fixtures and a Contact object (https://love2d.org/wiki/Contact).
A very good article: https://love2d.org/wiki/Tutorial:PhysicsCollisionCallbacks
You can use normalimpulse in postSolve() callback.
Here's the example:
force = ""
function love.load()
world = love.physics.newWorld(0, 200, true)
world:setCallbacks(beginContact, endContact, preSolve, postSolve)
ball = {}
ball.b = love.physics.newBody(world, 400,200, "dynamic")
ball.b:setMass(10)
ball.s = love.physics.newCircleShape(50)
ball.f = love.physics.newFixture(ball.b, ball.s)
ball.f:setRestitution(0.4) -- make it bouncy
ball.f:setUserData("Ball")
static = {}
static.b = love.physics.newBody(world, 400,400, "static")
static.s = love.physics.newRectangleShape(200,50)
static.f = love.physics.newFixture(static.b, static.s)
static.f:setUserData("Block")
text = "" -- we'll use this to put info text on the screen later
persisting = 0 -- we'll use this to store the state of repeated callback calls
end
function love.update(dt)
world:update(dt)
if love.keyboard.isDown("right") then
ball.b:applyForce(1000, 0)
elseif love.keyboard.isDown("left") then
ball.b:applyForce(-1000, 0)
end
if love.keyboard.isDown("up") then
ball.b:applyForce(0, -5000)
elseif love.keyboard.isDown("down") then
ball.b:applyForce(0, 1000)
end
if string.len(text) > 768 then -- cleanup when 'text' gets too long
text = ""
end
end
function love.draw()
love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius(), 20)
love.graphics.polygon("line", static.b:getWorldPoints(static.s:getPoints()))
love.graphics.print(text, 10, 10)
love.graphics.print(force, 100, 400)
end
function beginContact(a, b, coll)
x,y = coll:getNormal()
text = text.."\n"..a:getUserData().." colliding with "..b:getUserData().." with a vector normal of: "..x..", "..y
end
function endContact(a, b, coll)
persisting = 0
text = text.."\n"..a:getUserData().." uncolliding with "..b:getUserData()
end
function preSolve(a, b, coll)
if persisting == 0 then -- only say when they first start touching
text = text.."\n"..a:getUserData().." touching "..b:getUserData()
elseif persisting < 20 then -- then just start counting
text = text.." "..persisting
end
persisting = persisting + 1 -- keep track of how many updates they've been touching for
end
function postSolve(a, b, coll, normalimpulse, tangentimpulse)
force = normalimpulse
end
rigidbody.velocity.magnitude
is a velocity, not a force. And you can't get the force of a collision from the velocity of one object, you need information about the other object as well. Do you want to know how to get the velocity, or the force? And when do you want to get it? \$\endgroup\$ – MichaelHouse♦ Jan 1 '14 at 16:51