Looked around but don't see an easy way to do this. When adding a body to the world, is there a way to easily ask if that body is "on top" (colliding with) any existing body? Tried to process "collisionStart/End" but it looks like those happen only as bodies move around.
Two additions:
So comments would be welcome, otherwise you can close this issue. Thanks.
Try this:
var collision = Matter.SAT.collides(bodyA, bodyB);
if (collision.collided) {
// do something
}
Where bodyA is your new body and bodyB is some other body to check, so naturally you should loop this over every body that could be collided. For instance those from Composite.allBodies(world).
Actually, this might be a nice addition to Matter.Query!
Shamelessly stealing code, I created a routine that returns intersecting (colliding) bodies given a body and a filter. I use this to detect drag/drop collisions, but also to display intersections among bodies.
self.intersections = function (target, filter) {
var result = [],
oldFilter = target.collisionFilter;
target.collisionFilter = filter || FILTER_TILE;
var _getRegion = function (body) {
var grid = engine.broadphase,
bounds = body.bounds,
startCol = Math.floor(bounds.min.x / grid.bucketWidth),
endCol = Math.floor(bounds.max.x / grid.bucketWidth),
startRow = Math.floor(bounds.min.y / grid.bucketHeight),
endRow = Math.floor(bounds.max.y / grid.bucketHeight);
return {
id: startCol + ',' + endCol + ',' + startRow + ',' + endRow,
startCol: startCol,
endCol: endCol,
startRow: startRow,
endRow: endRow
}
};
var _getBucketId = function (column, row) {
return column + ',' + row;
},
i, row, col;
var region = _getRegion(target);
// var region = target.region;
for (col = region.startCol; col <= region.endCol; col++) {
for (row = region.startRow; row <= region.endRow; row++) {
var bucketId = _getBucketId(col, row),
bucket = engine.broadphase.buckets[bucketId];
// broad phase
if (bucket) {
for (i = 0; i < bucket.length; i++) {
var body = bucket[i];
if (body.id !== target.id) {
if (Matter.Detector.canCollide(target.collisionFilter, body.collisionFilter)) {
// mid phase
if (Matter.Bounds.overlaps(target.bounds, body.bounds)) {
parts_scan:
for (var j = target.parts.length > 1 ? 1 : 0; j < target.parts.length; j++) {
var partA = target.parts[j];
for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
var partB = body.parts[k];
if ((partA === target && partB === body) || Bounds.overlaps(partA.bounds, partB.bounds)) {
// narrow phase
var collision = Matter.SAT.collides(partA, partB);
if (collision.collided) {
if (!result.includes(body)) {
result.push(body);
}
break parts_scan;
}
}
}
}
}
}
}
}
}
}
}
target.collisionFilter = oldFilter;
return result;
};
I spent today creating a prototype of a pull request which would implement my collidingBodies idea. I want to make it efficient, so I want to leverage broadphase to narrow down the bodies to test.
I created a Grid.findBodies call to return all the bodies in buckets within a given bounds. And then I wrote a routine in my own application that would loop through these bodies and return
identified collisions for all the parts of the target with all the parts of the bodies.
In a "real" pull request I would generalize this more.
Although I'm happy to create a pull request, in studying your existing independent modules it is not clear where a routine such as mine would make sense. Any module I choose seems to introduce a new unnatural dependency for that module.
So my question is: would such a routine make sense in matterjs? Or should I just keep it in my codebase?
/**
* Given a bounds, returns contained bodies
*/
Grid.findBodies = function (grid, bounds) {
var i,
row,
col,
region = _getRegion(grid, {bounds:bounds}),
result = [];
for (col = region.startCol; col <= region.endCol; col++) {
for (row = region.startRow; row <= region.endRow; row++) {
var bucketId = _getBucketId(col, row),
bucket = grid.buckets[bucketId];
if (bucket) {
result.push.apply(result, bucket);
}
}
}
return result;
};
And the routine in my code:
self.collisions = function (target, filter) {
var result = {},
oldFilter = target.collisionFilter,
i,
grid = engine.broadphase,
bodies = grid.controller && grid.controller.findBodies ? grid.controller.findBodies(grid, target.bounds) : engine.world.bodies;
var makeResultKey = function (partA, partB) {
return partA.id + ":" + partB.id;
};
target.collisionFilter = filter || FILTER_TILE;
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
if (body.id !== target.id && (!target.ignoreId || target.ignoreId !== body.id)) {
if (Matter.Detector.canCollide(target.collisionFilter, body.collisionFilter)) {
// mid phase
if (Matter.Bounds.overlaps(target.bounds, body.bounds)) {
for (var j = target.parts.length > 1 ? 1 : 0; j < target.parts.length; j++) {
var partA = target.parts[j];
for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
var partB = body.parts[k];
if ((partA === target && partB === body) || Matter.Bounds.overlaps(partA.bounds, partB.bounds)) {
// narrow phase
var collision = Matter.SAT.collides(partA, partB);
if (collision.collided) {
var resultKey = makeResultKey(partA, partB);
if (!result[resultKey]) {
result[resultKey] = {target: partA, part: partB};
}
}
}
}
}
}
}
}
}
target.collisionFilter = oldFilter;
return result;
};
Can you put this in a jsfiddle giving an example of it working? Then I can get my head around it better!
Hey so I managed to check for collisions by using the Bounds.overlaps function. See example below:
....
var Bounds = Matter.Bounds;
....
function checkIfSpaceOccupied(cx, cy, approximateRange) {
var newBounds = {
min: {
x: cx - approximateRange,
y: cy - approximateRange
},
max: {
x: cx + approximateRange,
y: cy + approximateRange
}
}
for(var j = 0; j < worldObjects.length; j++) {
if (Bounds.overlaps(worldObjects[j].bounds, newBounds)) {
return true;
}
}
return false;
}
....
This example is not perfect as it is intended to be used with circular objects, but you guys get the idea.
Most helpful comment
Try this:
Where
bodyAis your new body andbodyBis some other body to check, so naturally you should loop this over every body that could be collided. For instance those fromComposite.allBodies(world).Actually, this might be a nice addition to
Matter.Query!