0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2024-12-28 14:09:01 -05:00

tweaks to collision filtering

This commit is contained in:
liabru 2014-07-29 13:14:31 +01:00
parent 3a32bdafd3
commit 5060c7626a
5 changed files with 106 additions and 47 deletions

View file

@ -49,6 +49,7 @@
<option value="softBody">Basic Soft Bodies</option> <option value="softBody">Basic Soft Bodies</option>
<option value="cloth">Cloth</option> <option value="cloth">Cloth</option>
<option value="events">Events</option> <option value="events">Events</option>
<option value="collisionFiltering">Collision Filtering</option>
<option value="chains">Chains</option> <option value="chains">Chains</option>
<option value="ballPool">Ball Pool</option> <option value="ballPool">Ball Pool</option>
<option value="stack">Stack</option> <option value="stack">Stack</option>
@ -61,7 +62,6 @@
<option value="beachBalls">Beach Balls</option> <option value="beachBalls">Beach Balls</option>
<option value="stress">Stress 1</option> <option value="stress">Stress 1</option>
<option value="stress2">Stress 2</option> <option value="stress2">Stress 2</option>
<option value="collisionFiltering">Collision Filtering</option>
</select> </select>
<input id="demo-reset" value="Reset" type="submit"> <input id="demo-reset" value="Reset" type="submit">
</div> </div>

View file

@ -448,12 +448,12 @@
Demo.chains = function() { Demo.chains = function() {
var _world = _engine.world, var _world = _engine.world,
groupId = Body.nextNonCollidingGroupId(); group = Body.nextGroup(true);
Demo.reset(); Demo.reset();
var ropeA = Composites.stack(200, 100, 5, 2, 10, 10, function(x, y, column, row) { var ropeA = Composites.stack(200, 100, 5, 2, 10, 10, function(x, y, column, row) {
return Bodies.rectangle(x, y, 50, 20, { collisionFilter: {group: groupId} }); return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } });
}); });
Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 });
@ -466,10 +466,10 @@
World.add(_world, ropeA); World.add(_world, ropeA);
groupId = Body.nextNonCollidingGroupId(); group = Body.nextGroup(true);
var ropeB = Composites.stack(500, 100, 5, 2, 10, 10, function(x, y, column, row) { var ropeB = Composites.stack(500, 100, 5, 2, 10, 10, function(x, y, column, row) {
return Bodies.circle(x, y, 20, { collisionFilter: {group: groupId} }); return Bodies.circle(x, y, 20, { collisionFilter: { group: group } });
}); });
Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 });
@ -485,12 +485,12 @@
Demo.bridge = function() { Demo.bridge = function() {
var _world = _engine.world, var _world = _engine.world,
groupId = Body.nextNonCollidingGroupId(); group = Body.nextGroup(true);
Demo.reset(); Demo.reset();
var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y, column, row) { var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y, column, row) {
return Bodies.rectangle(x, y, 50, 20, { collisionFilter: {group: groupId} }); return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } });
}); });
Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 }); Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 });
@ -937,8 +937,8 @@
Demo.reset(); Demo.reset();
var groupId = Body.nextNonCollidingGroupId(), var group = Body.nextGroup(true),
particleOptions = { friction: 0.00001, collisionFilter: { group: groupId }, render: { visible: false }}, particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }},
cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions); cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions);
for (var i = 0; i < 20; i++) { for (var i = 0; i < 20; i++) {
@ -1234,39 +1234,92 @@
Demo.collisionFiltering = function() { Demo.collisionFiltering = function() {
var _world = _engine.world; var _world = _engine.world;
// define our categories (as bit fields, there are up to 32 available)
var defaultCategory = 0x0001,
redCategory = 0x0002,
greenCategory = 0x0004,
blueCategory = 0x0008;
var redColor = '#C44D58',
blueColor = '#4ECDC4',
greenColor = '#C7F464';
Demo.reset(); Demo.reset();
var i; // create a stack with varying body categories (but these bodies can all collide with each other)
World.add(_world, World.add(_world,
Composites.stack(275, 150, 5, 10, 10, 10, function(x, y, column, row) { Composites.stack(275, 150, 5, 10, 10, 10, function(x, y, column, row) {
var category = redCategory,
color = redColor;
if (row > 5) {
category = blueCategory;
color = blueColor;
} else if (row > 2) {
category = greenCategory;
color = greenColor;
}
return Bodies.circle(x, y, 20, { return Bodies.circle(x, y, 20, {
collisionFilter: { collisionFilter: {
category: row < 7 ? 2 : 4 category: category
}, },
render: { render: {
strokeStyle: row < 7 ? 'red' : 'green', strokeStyle: color,
fillStyle: 'transparent' fillStyle: 'transparent'
} }
}); });
}) })
); );
// this body will only collide with the walls and the green bodies
World.add(_world,
Bodies.circle(310, 40, 30, {
collisionFilter: {
mask: defaultCategory | greenCategory
},
render: {
strokeStyle: Common.shadeColor(greenColor, -20),
fillStyle: greenColor
}
})
);
// this body will only collide with the walls and the red bodies
World.add(_world, World.add(_world,
Bodies.circle(400, 40, 30, { Bodies.circle(400, 40, 30, {
collisionFilter: { collisionFilter: {
mask: 5 mask: defaultCategory | redCategory
}, },
render: { render: {
fillStyle: 'blue' strokeStyle: Common.shadeColor(redColor, -20),
fillStyle: redColor
}
})
);
// this body will only collide with the walls and the blue bodies
World.add(_world,
Bodies.circle(480, 40, 30, {
collisionFilter: {
mask: defaultCategory | blueCategory
},
render: {
strokeStyle: Common.shadeColor(blueColor, -20),
fillStyle: blueColor
} }
}) })
); );
var renderOptions = _engine.render.options; var renderOptions = _engine.render.options;
renderOptions.wireframes = false; renderOptions.wireframes = false;
renderOptions.background = '#111'; renderOptions.background = '#222';
renderOptions.showCollisions = true; renderOptions.showAngleIndicator = false;
}; };
// the functions for the demo interface and controls below // the functions for the demo interface and controls below

View file

@ -51,7 +51,7 @@ var Body = {};
friction: 0.1, friction: 0.1,
frictionAir: 0.01, frictionAir: 0.01,
collisionFilter: { collisionFilter: {
category: 1, category: 0x0001,
mask: 0xFFFFFFFF, mask: 0xFFFFFFFF,
group: 0 group: 0
}, },
@ -75,21 +75,18 @@ var Body = {};
}; };
/** /**
* Returns the next unique groupID number for which bodies will collide. * Returns the next unique group index for which bodies will collide.
* @method nextCollidingGroupId * If `isNonColliding` is `true`, returns the next unique group index for which bodies will _not_ collide.
* @return {Number} Unique groupID * See `body.collisionFilter` for more information.
* @method nextGroup
* @param {bool} [isNonColliding=false]
* @return {Number} Unique group index
*/ */
Body.nextCollidingGroupId = function() { Body.nextGroup = function(isNonColliding) {
return _nextCollidingGroupId++; if (isNonColliding)
};
/**
* Returns the next collisionFilter.group value for which bodies will not collide.
* @method nextNonCollidingGroupId
* @return {Number} Unique groupID
*/
Body.nextNonCollidingGroupId = function() {
return _nextNonCollidingGroupId--; return _nextNonCollidingGroupId--;
return _nextCollidingGroupId++;
}; };
/** /**
@ -699,6 +696,7 @@ var Body = {};
* value is used as a bit field and the category should have only one bit set, meaning that * value is used as a bit field and the category should have only one bit set, meaning that
* the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32 * the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32
* different collision categories available. * different collision categories available.
*
* Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies * Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies
* the categories it collides with (the value is the bitwise AND value of all these categories). * the categories it collides with (the value is the bitwise AND value of all these categories).
* *
@ -711,7 +709,7 @@ var Body = {};
*/ */
/** /**
* An Integer `Number`, see `collisionFilter` * An Integer `Number`, see `body.collisionFilter` for more information.
* *
* @property collisionFilter.group * @property collisionFilter.group
* @type object * @type object
@ -719,7 +717,10 @@ var Body = {};
*/ */
/** /**
* An Integer `Number`, see `collisionFilter` * A bit field that specifies the collision category this body belongs to.
* The category value should have only one bit set, for example `0x0001`.
* This means there are up to 32 unique collision categories available.
* See `body.collisionFilter` for more information.
* *
* @property collisionFilter.category * @property collisionFilter.category
* @type object * @type object
@ -727,7 +728,7 @@ var Body = {};
*/ */
/** /**
* An Integer `Number`, see `collisionFilter` * An Integer `Number`, see `body.collisionFilter` for more information.
* *
* @property collisionFilter.mask * @property collisionFilter.mask
* @type object * @type object

View file

@ -26,13 +26,10 @@ var Detector = {};
var bodyA = broadphasePairs[i][0], var bodyA = broadphasePairs[i][0],
bodyB = broadphasePairs[i][1]; bodyB = broadphasePairs[i][1];
var collisionFilterA = bodyA.collisionFilter,
collisionFilterB = bodyB.collisionFilter;
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
continue; continue;
if (!_pairCollides(collisionFilterA, collisionFilterB)) if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
continue; continue;
metrics.midphaseTests += 1; metrics.midphaseTests += 1;
@ -88,10 +85,10 @@ var Detector = {};
// NOTE: could share a function for the below, but may drop performance? // NOTE: could share a function for the below, but may drop performance?
if (bodyA.groupId && bodyB.groupId && bodyA.groupId === bodyB.groupId) if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping))
continue; continue;
if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) if (!Detector.canCollide(bodyA.collisionFilter, bodyB.collisionFilter))
continue; continue;
metrics.midphaseTests += 1; metrics.midphaseTests += 1;
@ -129,11 +126,19 @@ var Detector = {};
return collisions; return collisions;
}; };
var _pairCollides = function(filterA, filterB) { /**
* Returns `true` if both supplied collision filters will allow a collision to occur.
* See `body.collisionFilter` for more information.
* @method canCollide
* @param {} filterA
* @param {} filterB
* @return {bool} `true` if collision can occur
*/
Detector.canCollide = function(filterA, filterB) {
if (filterA.group === filterB.group && filterA.group !== 0) if (filterA.group === filterB.group && filterA.group !== 0)
return filterA.group > 0; return filterA.group > 0;
return ((filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0); return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
}; };
})(); })();

View file

@ -226,7 +226,7 @@ var Composites = {};
* @return {composite} A new composite car body * @return {composite} A new composite car body
*/ */
Composites.car = function(xx, yy, width, height, wheelSize) { Composites.car = function(xx, yy, width, height, wheelSize) {
var collisionFilterGroup = Body.nextNonCollidingGroupId(), var group = Body.nextGroup(true),
wheelBase = -20, wheelBase = -20,
wheelAOffset = -width * 0.5 + wheelBase, wheelAOffset = -width * 0.5 + wheelBase,
wheelBOffset = width * 0.5 - wheelBase, wheelBOffset = width * 0.5 - wheelBase,
@ -235,7 +235,7 @@ var Composites = {};
var car = Composite.create({ label: 'Car' }), var car = Composite.create({ label: 'Car' }),
body = Bodies.trapezoid(xx, yy, width, height, 0.3, { body = Bodies.trapezoid(xx, yy, width, height, 0.3, {
collisionFilter: { collisionFilter: {
group: collisionFilterGroup group: group
}, },
friction: 0.01, friction: 0.01,
chamfer: { chamfer: {
@ -245,7 +245,7 @@ var Composites = {};
var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, {
collisionFilter: { collisionFilter: {
group: collisionFilterGroup group: group
}, },
restitution: 0.5, restitution: 0.5,
friction: 0.9, friction: 0.9,
@ -254,7 +254,7 @@ var Composites = {};
var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, {
collisionFilter: { collisionFilter: {
group: collisionFilterGroup group: group
}, },
restitution: 0.5, restitution: 0.5,
friction: 0.9, friction: 0.9,