Difference between revisions of "Tutorial:PhysicsCollisionCallbacks"
m |
(new screenshot) |
||
Line 189: | Line 189: | ||
== Finished == | == Finished == | ||
=== Screenshots === | === Screenshots === | ||
− | [[Image: | + | [[Image:Box2d-love-physics-callbacks-demo.png|thumb|Screenshot of the finished product.]] |
=== main.lua === | === main.lua === | ||
<source lang="lua"> | <source lang="lua"> |
Revision as of 22:44, 27 March 2012
Contents
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.
Tutorial
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(0,0, 800,600)
--Gravity is being set to 0 in the x direction and 40 in the y direction.
world:setGravity(0,40)
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()
... -- don't include this, it's just indicating where the existing code for the function should be
ball = {}
ball.b = love.physics.newBody(world, 400,200, 10,0)
ball.s = love.physics.newCircleShape(ball.b, 0,0, 50)
ball.s:setRestitution(0.4) -- make it bouncy
ball.s:setData("Ball")
static = {}
static.b = love.physics.newBody(world, 400,400, 0,0)
static.s = love.physics.newRectangleShape(static.b, 0,0, 200,50, 0)
static.s:setData("Block")
end
The objects are there now, but you can't yet see them. Let's draw them.
function love.draw()
love.graphics.circle("line", ball.b:getX(),ball.b:getY(), ball.s:getRadius(), 20)
love.graphics.polygon("line", static.s:getPoints())
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.
- Rem(ove) is the callback for any collision that stopped happening since last frame.
- Result (not yet implemented in Love).
function love.load()
... -- substitute for the rest of love.load
world = love.physics.newWorld(0,0, 800,600)
world:setGravity(0, 40)
--These callback function names can be almost any you want:
world:setCallbacks(add, persist, rem, result)
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
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 every time one of the collision actions happen. They pass in two shapes and a collision object. These parameters can also be named to whatever you want. In this tutorial, we choose a, b, and coll.
- a is the first object in the collision.
- b is the second object in the collision.
- coll is the contact object created.
Say we want to print to screen whenever a callback is called. We just need to modify the text variable we added to love.load() earlier by appending a string every time a collision action happens. We need a bit of extra code to keep the output clean too.
A list of functions you can use on contacts can be found at the Contact page.
function love.update(dt)
... -- substitute for the rest of love.update
if string.len(text) > 512 then -- cleanup when 'text' gets too long
text = ""
end
end
function love.draw()
... -- substitute for the rest of love.draw
love.graphics.print(text, 10, 10)
end
function add(a, b, coll)
persisting = 0 -- reset since every event other than persist means they're not continuing to touch
x,y = coll:getNormal()
text = text.."\n"..a.." colliding with "..b.." with a vector normal of: "..x..", "..y
end
function persist(a, b, coll)
if persisting == 0 then -- only say when they first start touching
text = text.."\n"..a.." touching "..b
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 rem(a, b, coll)
persisting = 0
text = text.."\n"..a.." uncolliding with "..b
end
function result(a, b, coll)
persisting = 0
text = text.."\n"..a.." hit "..b
end
And now you know how to use world callbacks!
To better explore how this world behaves and see when the callbacks are invoked, add some controls to allow you to push around the ball:
function love.update(dt)
world:update(dt)
if love.keyboard.isDown("right") then
ball.b:applyForce(100, 0)
elseif love.keyboard.isDown("left") then
ball.b:applyForce(-100, 0)
end
if love.keyboard.isDown("up") then
ball.b:applyForce(0, -100)
elseif love.keyboard.isDown("down") then
ball.b:applyForce(0, 100)
end
if string.len(text) > 512 then -- cleanup when 'text' gets too long
text = ""
end
end
Finished
Screenshots
main.lua
function love.load()
world = love.physics.newWorld(0, 0, 800, 600)
world:setGravity(0, 40)
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:setRestitution(0.4) -- make it bouncy
ball.s:setData("Ball")
static = {}
static.b = love.physics.newBody(world, 400,400, 0,0)
static.s = love.physics.newRectangleShape(static.b, 0,0, 200,50, 0)
static.s:setData("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(100, 0)
elseif love.keyboard.isDown("left") then
ball.b:applyForce(-100, 0)
end
if love.keyboard.isDown("up") then
ball.b:applyForce(0, -100)
elseif love.keyboard.isDown("down") then
ball.b:applyForce(0, 100)
end
if string.len(text) > 512 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.s:getPoints())
love.graphics.print(text, 10, 10)
end
function add(a, b, coll)
persisting = 0 -- reset since every event other than persist means they're not continuing to touch
x,y = coll:getNormal()
text = text.."\n"..a.." colliding with "..b.." with a vector normal of: "..x..", "..y
end
function persist(a, b, coll)
if persisting == 0 then -- only say when they first start touching
text = text.."\n"..a.." touching "..b
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 rem(a, b, coll)
persisting = 0
text = text.."\n"..a.." uncolliding with "..b
end
function result(a, b, coll)
persisting = 0
text = text.."\n"..a.." hit "..b
end
Other languages
Dansk –
Deutsch –
English –
Español –
Français –
Indonesia –
Italiano –
Lietuviškai –
Magyar –
Nederlands –
Polski –
Português –
Română –
Slovenský –
Suomi –
Svenska –
Türkçe –
Česky –
Ελληνικά –
Български –
Русский –
Српски –
Українська –
עברית –
ไทย –
日本語 –
正體中文 –
简体中文 –
Tiếng Việt –
한국어
More info