Reputation: 3279
I am working off the Slingshot demo. The problem is that after the rock is fired, it can still be clicked on and dragged around, which I want to disable.
I've added a filter to the rock:
var rockOptions = {
density: 0.004,
restitution: 0.75,
collisionFilter: { mask: SOLID, category: NEXTBALL }
};
And to the mouseconstraint:
var mouse = Mouse.create(render.canvas),
mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
collisionFilter: { category: NEXTBALL },
constraint: {
stiffness: 0.2,
render: {
visible: true
}
}
});
And then in the click event I attempt to change that filter, so it should no longer match the mouses category:
Events.on(engine, "afterUpdate", function () {
if (
mouseConstraint.mouse.button === -1 &&
(rock.position.x > shootPosition.x + 20 ||
rock.position.y < shootPosition.y - 20)
) {
Composite.remove(engine.world, elastic);
rock.collisionFilter = {category: SOLID, mask: SOLID};
}
});
But it still is draggable. I'm guessing the problem is how I'm changing the filter on the rock, but I don't see anything in the docs to suggest a way to change it.
I don't think it's because of the categories I've set up, but here they are just in case (the solid and image ones do work, the ball doesn't collide with image ones:
const SOLID = 0x0001;
const IMAGE = 0x0002;
const NEXTBALL = 0x0003;
Help me make the rock stop being clickable
Upvotes: 0
Views: 841
Reputation: 57195
Preventing the mouse from manipulating already-shot rocks can be achieved with two simple changes denoted by // <---
in the code snippet below.
rock.collisionFilter.category = 0b10;
sets the category to 2 for any rock that was just launched, before creating a new one and overwriting the rock
variable with the next rock to be launched.collisionFilter: {mask: 0b1},
sets the mask on the mouse constraint to only interact with bodies in category 1. Since disabled rocks are in category 2 (0b10
), the mouse will no longer interact with them.Here's the code in context. I used this commit in case anything changes.
Events.on(engine, 'afterUpdate', function() {
if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) {
rock.collisionFilter.category = 0b10; // <---
rock = Bodies.polygon(170, 450, 7, 20, rockOptions);
Composite.add(engine.world, rock);
elastic.bodyB = rock;
}
});
// add mouse control
var mouse = Mouse.create(render.canvas),
mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
collisionFilter: {mask: 0b1}, // <---
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
The default mask
value is 32 bits all set, or 4294967295
/0xffffffff
. You may wish to be more precise and disable only the second bit on the mouse constraint: 0xfffffffd
. This lets the mouse interact with anything but category 2 rather than just category 1.
The existing answer is correct that categories should be powers of two so that only one bit is set per category.
The reason rock.collisionFilter = {category: SOLID, mask: SOLID};
doesn't work is because it destroys the group
property.
See also:
Upvotes: 2
Reputation: 3279
Finally figured it out after much starting over, tweaking and examining different demos.
First the bitmasks for the categories have to be powers of two, so NEXTBALL
has to be 0x0004
rather than 0x0003
.
Next, you can't set the whole collisionFilter
object on an established body, or it breaks the collisions. Instead, you have to use rock.collisionFilter.category = NEXTBALL
;
Upvotes: 1