Skip to content

Commit

Permalink
Merge pull request #1238 from liabru/performance-2
Browse files Browse the repository at this point in the history
Improved performance and reduced memory usage
  • Loading branch information
liabru authored Mar 10, 2024
2 parents 962fba5 + 5e503e3 commit 4e6a8d9
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 159 deletions.
33 changes: 23 additions & 10 deletions examples/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ Example.remove = function() {
Events = Matter.Events;

// create engine
var engine = Engine.create(),
world = engine.world;
var engine = Engine.create({
enableSleeping: true
});

var world = engine.world;

// create renderer
var render = Render.create({
Expand All @@ -24,6 +27,7 @@ Example.remove = function() {
width: 800,
height: 600,
showAngleIndicator: true,
showSleeping: true
}
});

Expand All @@ -33,9 +37,6 @@ Example.remove = function() {
var runner = Runner.create();
Runner.run(runner, engine);

var stack = null,
lastTimestamp = 0;

var createStack = function() {
return Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) {
var sides = Math.round(Common.random(1, 8));
Expand All @@ -61,15 +62,28 @@ Example.remove = function() {
});
};

// add and remove stacks every few updates
var stack = null,
bottomStack = createStack(),
lastTimestamp = 0;

// add and remove bodies and composites every few updates
Events.on(engine, 'afterUpdate', function(event) {
// limit rate
if (stack && event.timestamp - lastTimestamp < 800) {
if (event.timestamp - lastTimestamp < 800) {
return;
}

lastTimestamp = event.timestamp;

// remove an old body
Composite.remove(bottomStack, bottomStack.bodies[0]);

// add a new body
Composite.add(
bottomStack,
Bodies.rectangle(Common.random(100, 500), 50, Common.random(25, 50), Common.random(25, 50))
);

// remove last stack
if (stack) {
Composite.remove(world, stack);
Expand All @@ -82,10 +96,9 @@ Example.remove = function() {
Composite.add(world, stack);
});

// add another stack that will not be removed
Composite.add(world, createStack());

Composite.add(world, [
bottomStack,

// walls
Bodies.rectangle(400, 0, 800, 50, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 50, { isStatic: true }),
Expand Down
10 changes: 10 additions & 0 deletions src/body/Composite.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,15 @@ var Body = require('./Body');
*/
Composite.removeComposite = function(compositeA, compositeB, deep) {
var position = Common.indexOf(compositeA.composites, compositeB);

if (position !== -1) {
var bodies = Composite.allBodies(compositeB);

Composite.removeCompositeAt(compositeA, position);

for (var i = 0; i < bodies.length; i++) {
bodies[i].sleepCounter = 0;
}
}

if (deep) {
Expand Down Expand Up @@ -244,8 +251,10 @@ var Body = require('./Body');
*/
Composite.removeBody = function(composite, body, deep) {
var position = Common.indexOf(composite.bodies, body);

if (position !== -1) {
Composite.removeBodyAt(composite, position);
body.sleepCounter = 0;
}

if (deep) {
Expand Down Expand Up @@ -296,6 +305,7 @@ var Body = require('./Body');
*/
Composite.removeConstraint = function(composite, constraint, deep) {
var position = Common.indexOf(composite.constraints, constraint);

if (position !== -1) {
Composite.removeConstraintAt(composite, position);
}
Expand Down
87 changes: 41 additions & 46 deletions src/collision/Collision.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ var Pair = require('./Pair');
normal: { x: 0, y: 0 },
tangent: { x: 0, y: 0 },
penetration: { x: 0, y: 0 },
supports: []
supports: [null, null],
supportCount: 0
};
};

Expand Down Expand Up @@ -99,27 +100,32 @@ var Pair = require('./Pair');
}

var normal = collision.normal,
tangent = collision.tangent,
penetration = collision.penetration,
supports = collision.supports,
depth = minOverlap.overlap,
minAxis = minOverlap.axis,
minAxisX = minAxis.x,
minAxisY = minAxis.y;
normalX = minAxis.x,
normalY = minAxis.y,
deltaX = bodyB.position.x - bodyA.position.x,
deltaY = bodyB.position.y - bodyA.position.y;

// ensure normal is facing away from bodyA
if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {
normal.x = minAxisX;
normal.y = minAxisY;
} else {
normal.x = -minAxisX;
normal.y = -minAxisY;
if (normalX * deltaX + normalY * deltaY >= 0) {
normalX = -normalX;
normalY = -normalY;
}

normal.x = normalX;
normal.y = normalY;

collision.tangent.x = -normal.y;
collision.tangent.y = normal.x;
tangent.x = -normalY;
tangent.y = normalX;

collision.depth = minOverlap.overlap;
penetration.x = normalX * depth;
penetration.y = normalY * depth;

collision.penetration.x = normal.x * collision.depth;
collision.penetration.y = normal.y * collision.depth;
collision.depth = depth;

// find support points, there is always either exactly one or two
var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),
Expand Down Expand Up @@ -152,8 +158,8 @@ var Pair = require('./Pair');
supports[supportCount++] = supportsB[0];
}

// update supports array size
supports.length = supportCount;
// update support count
collision.supportCount = supportCount;

return collision;
};
Expand Down Expand Up @@ -232,32 +238,6 @@ var Pair = require('./Pair');
result.overlap = overlapMin;
};

/**
* Projects vertices on an axis and returns an interval.
* @method _projectToAxis
* @private
* @param {} projection
* @param {} vertices
* @param {} axis
*/
Collision._projectToAxis = function(projection, vertices, axis) {
var min = vertices[0].x * axis.x + vertices[0].y * axis.y,
max = min;

for (var i = 1; i < vertices.length; i += 1) {
var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;

if (dot > max) {
max = dot;
} else if (dot < min) {
min = dot;
}
}

projection.min = min;
projection.max = max;
};

/**
* Finds supporting vertices given two bodies along a given direction using hill-climbing.
* @method _findSupports
Expand All @@ -275,15 +255,15 @@ var Pair = require('./Pair');
bodyAPositionY = bodyA.position.y,
normalX = normal.x * direction,
normalY = normal.y * direction,
nearestDistance = Number.MAX_VALUE,
vertexA,
vertexB,
vertexA = vertices[0],
vertexB = vertexA,
nearestDistance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y),
vertexC,
distance,
j;

// find deepest vertex relative to the axis
for (j = 0; j < verticesLength; j += 1) {
for (j = 1; j < verticesLength; j += 1) {
vertexB = vertices[j];
distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);

Expand Down Expand Up @@ -398,11 +378,26 @@ var Pair = require('./Pair');

/**
* An array of body vertices that represent the support points in the collision.
*
* _Note:_ Only the first `collision.supportCount` items of `collision.supports` are active.
* Therefore use `collision.supportCount` instead of `collision.supports.length` when iterating the active supports.
*
* These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.
*
* @property supports
* @type vector[]
* @default []
*/

/**
* The number of active supports for this collision found in `collision.supports`.
*
* _Note:_ Only the first `collision.supportCount` items of `collision.supports` are active.
* Therefore use `collision.supportCount` instead of `collision.supports.length` when iterating the active supports.
*
* @property supportCount
* @type number
* @default 0
*/

})();
2 changes: 1 addition & 1 deletion src/collision/Contact.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = Contact;
/**
* Creates a new contact.
* @method create
* @param {vertex} vertex
* @param {vertex} [vertex]
* @return {contact} A new contact
*/
Contact.create = function(vertex) {
Expand Down
22 changes: 18 additions & 4 deletions src/collision/Detector.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var Collision = require('./Collision');
Detector.create = function(options) {
var defaults = {
bodies: [],
collisions: [],
pairs: null
};

Expand All @@ -45,6 +46,7 @@ var Collision = require('./Collision');
*/
Detector.clear = function(detector) {
detector.bodies = [];
detector.collisions = [];
};

/**
Expand All @@ -57,12 +59,13 @@ var Collision = require('./Collision');
* @return {collision[]} collisions
*/
Detector.collisions = function(detector) {
var collisions = [],
pairs = detector.pairs,
var pairs = detector.pairs,
bodies = detector.bodies,
bodiesLength = bodies.length,
canCollide = Detector.canCollide,
collides = Collision.collides,
collisions = detector.collisions,
collisionIndex = 0,
i,
j;

Expand Down Expand Up @@ -104,7 +107,7 @@ var Collision = require('./Collision');
var collision = collides(bodyA, bodyB, pairs);

if (collision) {
collisions.push(collision);
collisions[collisionIndex++] = collision;
}
} else {
var partsAStart = partsALength > 1 ? 1 : 0,
Expand All @@ -126,14 +129,18 @@ var Collision = require('./Collision');
var collision = collides(partA, partB, pairs);

if (collision) {
collisions.push(collision);
collisions[collisionIndex++] = collision;
}
}
}
}
}
}

if (collisions.length !== collisionIndex) {
collisions.length = collisionIndex;
}

return collisions;
};

Expand Down Expand Up @@ -180,6 +187,13 @@ var Collision = require('./Collision');
* @default []
*/

/**
* The array of `Matter.Collision` found in the last call to `Detector.collisions` on this detector.
* @property collisions
* @type collision[]
* @default []
*/

/**
* Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
* @property pairs
Expand Down
Loading

0 comments on commit 4e6a8d9

Please sign in to comment.