Thank you for visiting my thread.
I need a solution for my current problem with love.physics. Let's imagine that I have 3 bodies attached with their own shapes with fixtures, they're called A, B, and C. I need to make body A not collide with body B (go through) but collides with body C. After quite some time (maybe 5 seconds), body A can collide with body B and C.
Anyone has the solution?
Note: I'm on phone right now so asking for *.love file is impossible.
Specific Collisions
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Specific Collisions
This worked for me:
Tested with love2d 0.8.0, 0.9.1, 0.9.2 and 0.10.1.
I tried to use [wiki]World:setContactFilter[/wiki] but it didn't trigger. Does anyone know why? Edit: got it working.
Code: Select all
lp = love.physics
lg = love.graphics
lm = love.mouse
local LMB = love._version_major*10+love._version_minor < 10 and "l" or 1
local world = lp.newWorld(0, 300, false)
local objects = {
A = {
body = lp.newBody(world, 200, 300, "dynamic");
shape = lp.newCircleShape(50);
color = { 255, 128, 0 };
};
B = {
body = lp.newBody(world, 400, 300, "dynamic");
shape = lp.newCircleShape(50);
color = { 128, 255, 0 };
};
C = {
body = lp.newBody(world, 600, 300, "dynamic");
shape = lp.newCircleShape(50);
color = { 255, 255, 0 };
};
}
objects.A.fixture = lp.newFixture(objects.A.body, objects.A.shape)
objects.B.fixture = lp.newFixture(objects.B.body, objects.B.shape)
objects.C.fixture = lp.newFixture(objects.C.body, objects.C.shape)
-- Enclosing box is in categories 0-14 and collides with categories 0-14
do
local body = lp.newBody(world, 400, 300)
lp.newFixture(body, lp.newEdgeShape(-396, -296, 396, -296)):setFilterData(32767, 32767, 0)
lp.newFixture(body, lp.newEdgeShape(-396, 296, 396, 296)):setFilterData(32767, 32767, 0)
lp.newFixture(body, lp.newEdgeShape(-396, -296, -396, 296)):setFilterData(32767, 32767, 0)
lp.newFixture(body, lp.newEdgeShape( 396, -296, 396, 296)):setFilterData(32767, 32767, 0)
end
-- Object A is in category 1 and collides with category 0
objects.A.fixture:setFilterData(2, 1, 0)
-- Object B is in category 1 and collides with category 1
objects.B.fixture:setFilterData(2, 2, 0)
-- Object C is in categories 0 and 1 and collides with categories 0 and 1
objects.C.fixture:setFilterData(3, 3, 0)
local font = lg.newFont(40)
lg.setFont(font)
local fontH = font:getHeight()
function love.update(dt)
if lm.isDown(LMB) then
local mx, my = lm.getPosition()
local closest, closestd2
for k, v in next, objects do
local x, y = v.body:getPosition()
local d2 = (x-mx)^2 + (y-my)^2
if not closest or d2 < closestd2 then
closest, closestd2 = k, d2
end
end
objects[closest].body:setPosition(mx, my)
objects[closest].body:setLinearVelocity(0, 0)
objects[closest].body:setAngularVelocity(0)
end
world:update(dt)
end
function love.draw()
for k, v in next,objects do
lg.setColor(v.color)
local x, y = v.body:getPosition()
local fontW = font:getWidth(k)
lg.circle("line", x, y, v.shape:getRadius())
lg.print(k, x, y, v.body:getAngle(), 1, 1, fontW/2, fontH/2)
end
lg.setColor(255, 255, 255)
lg.rectangle("line", 3.5, 3.5, 793, 593)
if collideAB then
lg.setColor(0, 255, 0)
lg.print("A-B collision enabled", 4, 4)
else
lg.setColor(255, 0, 0)
lg.print("A-B collision disabled", 4, 4)
end
end
function love.keypressed(k)
if k == "space" or k == " " or k == "return" then
collideAB = not collideAB
-- Toggle object A colliding with category 1 (true) or 0 (false)
objects.A.fixture:setFilterData(2, collideAB and 2 or 1, 0)
end
if k == "escape" then love.event.quit() end
end
Last edited by pgimeno on Fri May 13, 2016 6:27 pm, edited 1 time in total.
Re: Specific Collisions
pgimeno, thank you. But can you explain how this Fixture:setFilterData works? It's hard for me to grasp it.
Re: Specific Collisions
You need the first two parameters, I'm still not sure what the last one is for.
The first one is the categories of the fixture, one bit per category, up to 16.
The second one is the mask (the categories of other fixtures it will collide with).
The number 1 has bit 0 set and the rest clear. If used as a category number, the fixture will be in category 0 and not in categories 1-15. If used as a mask number, it will only collide with those fixtures that have category 0 set.
The number 2 has bit 1 set and the rest clear. If used as a category number, it will be in category 1 and not in categories 0 nor 2-15. If used as a mask number, it will only collide with those fixtures that have category 1 set.
The number 3 has bits 0 and 1 set. If used as a category number, it will be in categories 0 and 1 and not in categories 2-15. If used as a mask number, it will only collide with those fixtures that have either category 0 or category 1 set.
And so on. I've set up the borders to be in (and collide with) categories 0-14 and not in/with category 15 (in case you want a category guaranteed not to collide with anything, not even borders), then objects A and B in category 1 and object C in categories 0 and 1.
A only collides with category 0 if collision between A and B is not desired, and with category 1 if it is.
B collides only with category 1.
C collides with categories 0 and 1.
I could have also made A switch to category 0 while collision between A and B is not desired, so that the categories were more isolated, but I found that to be unnecessary in this particular instance, saving a bit of extra code.
A bit of a mess, but it works
The first one is the categories of the fixture, one bit per category, up to 16.
The second one is the mask (the categories of other fixtures it will collide with).
The number 1 has bit 0 set and the rest clear. If used as a category number, the fixture will be in category 0 and not in categories 1-15. If used as a mask number, it will only collide with those fixtures that have category 0 set.
The number 2 has bit 1 set and the rest clear. If used as a category number, it will be in category 1 and not in categories 0 nor 2-15. If used as a mask number, it will only collide with those fixtures that have category 1 set.
The number 3 has bits 0 and 1 set. If used as a category number, it will be in categories 0 and 1 and not in categories 2-15. If used as a mask number, it will only collide with those fixtures that have either category 0 or category 1 set.
And so on. I've set up the borders to be in (and collide with) categories 0-14 and not in/with category 15 (in case you want a category guaranteed not to collide with anything, not even borders), then objects A and B in category 1 and object C in categories 0 and 1.
A only collides with category 0 if collision between A and B is not desired, and with category 1 if it is.
B collides only with category 1.
C collides with categories 0 and 1.
I could have also made A switch to category 0 while collision between A and B is not desired, so that the categories were more isolated, but I found that to be unnecessary in this particular instance, saving a bit of extra code.
A bit of a mess, but it works
Re: Specific Collisions
How can I make it work with more than 3 bodies in the world?
Re: Specific Collisions
It depends on what you want them to collide with. If all the other objects can collide with each other, including A and B, just do the same as in object C: add them to categories 0 and 1 and let them collide with categories 0 and 1.
Re: Specific Collisions
OK, I'm trying to do it with your way. But I think I found a way but not so sure though. The way is that I use
Thank you either way!
Code: Select all
world:setCallbacks(function(fixture1, fixture2, contact)
contact:setEnabled(false)
end)
Re: Specific Collisions
I must have made something wrong before, but I tested this again and it worked this time:
(and removing all setFilterData calls everywhere). That callback is intended for exactly this purpose, so you may find it easier.
The setFilterData method is instantaneous: it immediately pushes A and B away when activating collisions between them and they're intersecting. This one isn't always instantaneous.
Code: Select all
world:setContactFilter(function (f1, f2)
if f1 == objects.A.fixture and f2 == objects.B.fixture
or f1 == objects.B.fixture and f2 == objects.A.fixture then
return collideAB
end
return true
end)
The setFilterData method is instantaneous: it immediately pushes A and B away when activating collisions between them and they're intersecting. This one isn't always instantaneous.
Who is online
Users browsing this forum: Bing [Bot] and 202 guests