Tutorial:PhysicsCollisionCallbacks

Preface

If you do not have a good grasp on love.physics, you should first check out this physics tutorial.

In this tutorial we will create a collision between two objects that calls certain callbacks set by World:setCallbacks.

main.lua setup

I usually start every main.lua with 3 love functions: love.load, love.update, and love.draw

function love.load()
 
end
function love.update(dt)
 
end
function love.draw()
 
end

World setup

Now that we have a framework setup, let's setup a physics world in love.load with newWorld.

Also we will use World:setGravity and World:update.

function love.load()
	--Store the new world in a variable such as "world"
	world = love.physics.newWorld(800,600)
		--Gravity is being set to 0 in the x direction and 20 in the y direction.
		world:setGravity(0,20)
end
 
function love.update(dt)
	--Never forget to update your world every frame.
	world:update(dt)
end

Now we want to create a ball and a ground. To do this we will need newBody, newCircleShape, and newRectangleShape.

function love.load()
	--Store the new world in a variable such as "world"
	world = love.physics.newWorld(800,600)
		--Gravity is being set to 0 in the x direction and 20 in the y direction.
		world:setGravity(0,20)
	ball = {}
		ball.b = love.physics.newBody(world, 400,200, 10,0)
		ball.s = love.physics.newCircleShape(ball.b, 0,0, 50)
		ball.s:setData("Ball")
	static = {}
		static.b = love.physics.newBody(world, 400,400, 0,0)
		static.s = love.physics.newRectangleShape(static.b, -100,-25, 200,50, 0)
		static.s:setData("Block")
end

The balls are there now, but you can't yet see them. Let's draw them. This can be a bit tricky at times to match up the origins of objects.

function love.draw()
	love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius())
	local x1,y1, _,_, x3,y3, _,_ = static.s:getBoundingBox()
	local w = x3-x1
	local h = y3-y1
	love.graphics.rectangle("line",
		static.b:getX()-w/2,static.b:getY(),
		w,h, 0)
end

Now we should see a ball fall down and hit a solid rectangle.

World Callbacks

But what if we want more information on the two objects colliding? Now we will use World:setCallbacks to further dissect their collision(s).

First thing we do is set the world callbacks with World:setCallbacks. There are four callbacks for a collision: add, persist, remove, and result.

Add is the callback for every new collision.
Persist is the callback for every collision that is continuing from last frame.
Remove is the callback for any collision that stopped happening since last frame.
Result is the callback for ???.
function love.load()
	--Store the new world in a variable such as "world"
	world = love.physics.newWorld(800,600)
		--Gravity is being set to 0 in the x direction and 20 in the y direction.
		world:setGravity(0,20)
		--Can be almost any function names you want.
		world:setCallbacks(add, persist, rem, result)
	ball = {}
		ball.b = love.physics.newBody(world, 400,200, 10,0)
		ball.s = love.physics.newCircleShape(ball.b, 0,0, 50)
		ball.s:setData("Ball")
	static = {}
		static.b = love.physics.newBody(world, 400,400, 0,0)
		static.s = love.physics.newRectangleShape(static.b, -100,-25, 200,50, 0)
		static.s:setData("Block")
end

Now define each function you just named.

function add(a, b, coll)
 
end
 
function persist(a, b, coll)
 
end
 
function rem(a, b, coll)
 
end
 
function result(a, b, coll)
 
end

These functions are called everytime one of the collision actions happen.

Say we want to print to screen whenever a callback is called. All we have to do is create a variable to store the strings and then append to the string everytime a collision action happens.

text = ""
function add(a, b, coll)
	text = text..a.." collding with "..b.." at an angle of "..coll:getNormal().."\n"
end
 
function persist(a, b, coll)
	text = text..a.." touching "..b.."\n"
end
 
function rem(a, b, coll)
	text = text..a.." uncolliding "..b.."\n"
end
 
function result(a, b, coll)
	text = text..a.." hit "..b.."resulting with "..coll:getNormal().."\n"
end

And now you know how to use world callbacks!

File:WorldCallbacksTutorial.png
Screenshot of the finished product.

Entire Thing

function love.load()
world = love.physics.newWorld(800,600)
	world:setGravity(0,20)
	world:setCallbacks(add, persist, rem, result)
	ball = {}
		ball.b = love.physics.newBody(world, 400,200, 10,0)
		ball.s = love.physics.newCircleShape(ball.b, 0,0, 50)
		ball.s:setData("Ball")
	static = {}
		static.b = love.physics.newBody(world, 400,400, 0,0)
		static.s = love.physics.newRectangleShape(static.b, -100,-25, 200,50, 0)
		static.s:setData("Block")
end
 
function love.update(dt)
	world:update(dt)
end
 
function love.draw()
	love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius())
	local x1,y1, _,_, x3,y3, _,_ = static.s:getBoundingBox()
	local w = x3-x1
	local h = y3-y1
	love.graphics.rectangle("line",
		static.b:getX()-w/2,static.b:getY(),
		w,h, 0)
	love.graphics.print(text,0,12)
end
 
--Refer to http://love2d.org/wiki/Contact for more information on collision objects
--'coll' is an object created by the collision
--'a' is the first object in the collision and 'b' is the second
 
text = ""
 
function add(a, b, coll)
	text = text..a.." collding with "..b.." at an angle of "..coll:getNormal().."\n"
end
 
function persist(a, b, coll)
	text = text..a.." touching "..b.."\n"
end
 
function rem(a, b, coll)
	text = text..a.." uncolliding "..b.."\n"
end
 
function result(a, b, coll)
	text = text..a.." hit "..b.."resulting with "..coll:getNormal().."\n"
end