While creating my own version of the Matter.js slingshot demo[source] I got stuck while trying to prevent the projectile from being draggable after it was shot.
TL;DR
Looking for some guidance to stop the projectile from being draggable after it was fired.
My attempt:
Create 3 collisionFilter categories;
- 0x0001:
static
: Ground, platform, etc - 0x0002:
drag
: Items that interact with mouse - 0x0004:
nodrag
: Items that cannot interact with the mouse, but does collide with everything else
This works great, everything collides with each other, and I'm only able to drag the projectile (drag
), not the targets (nodrag
).
So my next challenge was to toggle the projectile from drag
to nodrag
after it was fired. Otherwise, you can grep the projectile and use it like a Wrecking Ball.
So Just before I add a new projectile to the elastic, I've tried toggling the collisionFilter
to nodrag
using the following code:
Events.on(engine, 'afterUpdate', function() {
// If Rock is outside drag-range
if (mouseConstraint.mouse.button === -1 && (rock.position.x > dragborder_x || rock.position.y < dragborder_y)) {
rock.collisionFilter = { category: cat.nodrag };
...
Problem^^
Unfortunately this prevents the projectile from colliding with everything, even the walls (static
). Even the targets with nodrag
collide with the walls. So I have no clue why the projectile stops colliding after switching to nodrag
.
Simplified example
- Toggle line 72 to see the problem as described above
// Failed attempt (line 72) // rock.collisionFilter = { category: cat.nodrag };
// Statics
const vw = window.innerWidth;
const vh = window.innerHeight;
var Engine = Matter.Engine, Render = Matter.Render, Runner = Matter.Runner, Composites = Matter.Composites, Events = Matter.Events, Constraint = Matter.Constraint, MouseConstraint = Matter.MouseConstraint, Mouse = Matter.Mouse, World = Matter.World, Bodies = Matter.Bodies;
const cat = {
static: 0x0001,
nodrag: 0x0002,
drag: 0x0004
};
// Create world
var engine = Engine.create();
var world = engine.world;
// Create render
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: vw,
height: vh,
wireframes: false,
showAngleIndicator: false
}
});
// render.on()
Render.run(render);
// Create runner
var runner = Runner.create();
Runner.run(runner, engine);
// Body consts
const rock_x = vw * .20;
const rock_y = vh * .66;
const rockOptions = {
density: 0.01,
collisionFilter: {
category: cat.drag
}
};
const gift = {
render: {
sprite: {}
},
collisionFilter: {
category: cat.nodrag
}
};
// Add Static bodies
var ground = Bodies.rectangle(vw * .5, vh * .9, vw * .9, 42, { isStatic: true, render: { fillStyle: '#060a19' } });
var rock = Bodies.polygon(rock_x, rock_y, 8, 15, rockOptions);
var anchor = { x: rock_x, y: rock_y };
var elastic = Constraint.create({ pointA: anchor, bodyB: rock, stiffness: 0.09, render: { lineWidth: 1 } });
var wall = Composites.stack(vw * .66, 0, 2, (vh * .4) / 15, 1, 0, (x, y) => Bodies.rectangle(x, y, 15, 15, gift));
var platform = Bodies.rectangle(vw * .75, vh * .6, 210, 21, { isStatic: true, render: { fillStyle: '#060a19' }, collisionFilter: { category: cat.static } });
var pyramid = Composites.pyramid(vw * .30, 0, 11, 11, 0, 0, (x, y) => Bodies.rectangle(x, y, 15, 15, gift));
World.add(engine.world, [ ground, pyramid, platform, wall, rock, elastic ]);
// Rock drag
const dragborder_x = rock_x + 20;
const dragborder_y = rock_y - 20;
Events.on(engine, 'afterUpdate', function() {
// If Rock is outside drag-range
if (mouseConstraint.mouse.button === -1 && (rock.position.x > dragborder_x || rock.position.y < dragborder_y)) {
// Failed attempt (line 72)
// rock.collisionFilter = { category: cat.nodrag };
// Add new Rock
rock = Bodies.polygon(rock_x, rock_y, 7, 15, rockOptions);
World.add(engine.world, rock);
// Re-bind elastic
elastic.bodyB = rock;
}
});
// Mouse control
var mouse = Mouse.create(render.canvas);
var mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false
}
}
});
// Add mouse
World.add(world, mouseConstraint);
render.mouse = mouse;
// Prevent mouse-drag
mouseConstraint.collisionFilter.mask = cat.static | cat.drag;
// Run
Engine.run(engine);
Render.run(render);
<script src="https://cdn.jsdelivr.net/npm/matter-js@0.16.1/build/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,minimal-ui">