Skip to content

Commit

Permalink
The MatterAttractors plugin, which enables attractors between bodie…
Browse files Browse the repository at this point in the history
…s, has been fixed. The original plugin only worked if the body with the attractor was _first_ in the world bodies list. It can now attract any body, no matter where in the world list it is. Fix #5160
  • Loading branch information
photonstorm committed Jul 23, 2020
1 parent 0999824 commit fb1306e
Showing 1 changed file with 113 additions and 96 deletions.
209 changes: 113 additions & 96 deletions src/physics/matter-js/lib/plugins/MatterAttractors.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,108 +5,125 @@ var Matter = require('../../CustomMain');
* See the readme for usage and examples.
* @module MatterAttractors
*/
var MatterAttractors = {
// plugin meta
name: 'matter-attractors', // PLUGIN_NAME
version: '0.1.7', // PLUGIN_VERSION
for: 'matter-js@^0.14.2',
silent: true, // no console log please

// installs the plugin where `base` is `Matter`
// you should not need to call this directly.
install: function(base) {
base.after('Body.create', function() {
MatterAttractors.Body.init(this);
});

base.before('Engine.update', function(engine) {
MatterAttractors.Engine.update(engine);
});
},

Body: {
/**
* Initialises the `body` to support attractors.
* This is called automatically by the plugin.
* @function MatterAttractors.Body.init
* @param {Matter.Body} body The body to init.
* @returns {void} No return value.
*/
init: function(body) {
body.plugin.attractors = body.plugin.attractors || [];
}
},

Engine: {
/**
* Applies all attractors for all bodies in the `engine`.
* This is called automatically by the plugin.
* @function MatterAttractors.Engine.update
* @param {Matter.Engine} engine The engine to update.
* @returns {void} No return value.
*/
update: function(engine) {
var world = engine.world,
bodies = Matter.Composite.allBodies(world);

for (var i = 0; i < bodies.length; i += 1) {
var bodyA = bodies[i],
attractors = bodyA.plugin.attractors;

if (attractors && attractors.length > 0) {
for (var j = i + 1; j < bodies.length; j += 1) {
var bodyB = bodies[j];

for (var k = 0; k < attractors.length; k += 1) {
var attractor = attractors[k],
forceVector = attractor;

if (Matter.Common.isFunction(attractor)) {
forceVector = attractor(bodyA, bodyB);
}

if (forceVector) {
Matter.Body.applyForce(bodyB, bodyB.position, forceVector);
}
var MatterAttractors =
{
name: 'matter-attractors',
version: '0.1.7',
for: 'matter-js@^0.14.2',
silent: true,

// installs the plugin where `base` is `Matter`
// you should not need to call this directly.
install: function (base)
{
base.after('Body.create', function ()
{
MatterAttractors.Body.init(this);
});

base.before('Engine.update', function (engine)
{
MatterAttractors.Engine.update(engine);
});
},

Body:
{
/**
* Initialises the `body` to support attractors.
* This is called automatically by the plugin.
* @function MatterAttractors.Body.init
* @param {Matter.Body} body The body to init.
* @returns {void} No return value.
*/
init: function (body)
{
body.plugin.attractors = body.plugin.attractors || [];
}
},

Engine:
{
/**
* Applies all attractors for all bodies in the `engine`.
* This is called automatically by the plugin.
* @function MatterAttractors.Engine.update
* @param {Matter.Engine} engine The engine to update.
* @returns {void} No return value.
*/
update: function (engine)
{
var bodies = Matter.Composite.allBodies(engine.world);

for (var i = 0; i < bodies.length; i++)
{
var bodyA = bodies[i];
var attractors = bodyA.plugin.attractors;

if (attractors && attractors.length > 0)
{
for (var j = 0; j < bodies.length; j++)
{
var bodyB = bodies[j];

if (i !== j)
{
for (var k = 0; k < attractors.length; k++)
{
var attractor = attractors[k];
var forceVector = attractor;

if (Matter.Common.isFunction(attractor))
{
forceVector = attractor(bodyA, bodyB);
}

if (forceVector)
{
Matter.Body.applyForce(bodyB, bodyB.position, forceVector);
}
}
}
}
}
}
}
}
}
}
},

/**
* Defines some useful common attractor functions that can be used
* by pushing them to your body's `body.plugin.attractors` array.
* @namespace MatterAttractors.Attractors
* @property {number} gravityConstant The gravitational constant used by the gravity attractor.
*/
Attractors: {
gravityConstant: 0.001,
},

/**
* An attractor function that applies Newton's law of gravitation.
* Use this by pushing `MatterAttractors.Attractors.gravity` to your body's `body.plugin.attractors` array.
* The gravitational constant defaults to `0.001` which you can change
* at `MatterAttractors.Attractors.gravityConstant`.
* @function MatterAttractors.Attractors.gravity
* @param {Matter.Body} bodyA The first body.
* @param {Matter.Body} bodyB The second body.
* @returns {void} No return value.
* Defines some useful common attractor functions that can be used
* by pushing them to your body's `body.plugin.attractors` array.
* @namespace MatterAttractors.Attractors
* @property {number} gravityConstant The gravitational constant used by the gravity attractor.
*/
gravity: function(bodyA, bodyB) {
// use Newton's law of gravitation
var bToA = Matter.Vector.sub(bodyB.position, bodyA.position),
distanceSq = Matter.Vector.magnitudeSquared(bToA) || 0.0001,
normal = Matter.Vector.normalise(bToA),
magnitude = -MatterAttractors.Attractors.gravityConstant * (bodyA.mass * bodyB.mass / distanceSq),
force = Matter.Vector.mult(normal, magnitude);

// to apply forces to both bodies
Matter.Body.applyForce(bodyA, bodyA.position, Matter.Vector.neg(force));
Matter.Body.applyForce(bodyB, bodyB.position, force);
Attractors:
{
gravityConstant: 0.001,

/**
* An attractor function that applies Newton's law of gravitation.
* Use this by pushing `MatterAttractors.Attractors.gravity` to your body's `body.plugin.attractors` array.
* The gravitational constant defaults to `0.001` which you can change
* at `MatterAttractors.Attractors.gravityConstant`.
* @function MatterAttractors.Attractors.gravity
* @param {Matter.Body} bodyA The first body.
* @param {Matter.Body} bodyB The second body.
* @returns {void} No return value.
*/
gravity: function (bodyA, bodyB)
{
// use Newton's law of gravitation
var bToA = Matter.Vector.sub(bodyB.position, bodyA.position);
var distanceSq = Matter.Vector.magnitudeSquared(bToA) || 0.0001;
var normal = Matter.Vector.normalise(bToA);
var magnitude = -MatterAttractors.Attractors.gravityConstant * (bodyA.mass * bodyB.mass / distanceSq);
var force = Matter.Vector.mult(normal, magnitude);

// to apply forces to both bodies
Matter.Body.applyForce(bodyA, bodyA.position, Matter.Vector.neg(force));
Matter.Body.applyForce(bodyB, bodyB.position, force);
}
}
}
};

module.exports = MatterAttractors;
Expand Down

0 comments on commit fb1306e

Please sign in to comment.