I've built a physics simulator which uses Newton's Gravity equation to simulate gravity between some given objects. The problem is, for the objects to attract each other, I need to give them a negative mass for example (mass: -10000000) if I give them a positive mass, they repel each other.
Here is the code for the physics engine
class physicsStepper {
/**
* Create a physicsStepper class
* @param {Object} configs - Configs for the physics stepper. (Optional)
* @param {number} configs.G - The Gravitational Constant.
* @param {boolean} configs.collisions - Whether or not to detect collisions.
* @param {number} configs.simulationBounds - The size of the simulation used to create a Quadtree.
* @param {number} configs.subdivisions - number of nodes for the Quadtree.
*/
constructor(configs = {}) {
//default configs
Object.assign(this, {
G: 6.6743 * Math.pow(10, -11),
collisions: false,
dimensions: 2,
useGrid: false,
simSize: {
height: 1600,
width: 1600,
},
});
//apply changes
Object.assign(this, configs);
//setup Grid
if (this.useGrid) this.grid = new grid();
}
/**
* Circle vs circle collider
* @param {Object} a - A particle object with radius
* @param {Object} b - A particle object with radius
* @param {number} r - The distance between the two objects
* @returns {boolean} - Whether a collision happened or not
*/
collider(a, b, r) {
if (r < a.radius b.radius) return true;
else return false;
}
/**
* Apply force to an entity
* @param {Object} entity - a physics object
* @param {Object} force - a force vector2
*/
applyForce(entity, force) {
force.divideScalar(entity.mass);
entity.acceleration.add(force);
}
/**
* Calculate the attraction between two objects
* @param {Object} a - A particle object with radius
* @param {Object} b - A particle object with radius
* @returns {Object} data.r - the distance between the two entities
* @returns {Object} data.force - the force of attraction between the two entities
*/
calcAttraction(a, b) {
const { G } = this;
const force = new Vector2();
force.subVectors(a.position, b.position);
const r = $.distance(a, b);
force.normalize();
const strength = ((G * a.mass * b.mass) / r) * r;
force.multiplyScalar(strength);
return { r, force };
}
/**
* Translate the entity to its new position by using it's velocity vector2
* @param {Object} entity - A physics object
*/
translatePositions(entity) {
entity.velocity.add(entity.acceleration);
entity.position.add(entity.velocity);
entity.acceleration.multiplyScalar(0);
}
/**
* Calculates and updates all physics objects
* @param {Object[]} scene - The scene containing the physics objects (required)
* @param {Number} delta - The delta time (required)
*/
step(scene, dt) {
for (let [i, a] of scene.children.entries()) {
if (!a.physics) continue;
for (let b of scene.children) {
if (!b.physics) continue;
if (a.sn === b.sn) continue;
const { r, force } = this.calcAttraction(a, b);
if (this.collisions && this.collider(a, b, r)) {
a.velocity.multiplyScalar(0.999);
b.velocity.multiplyScalar(0.999);
}
force.multiplyScalar(dt);
this.applyForce(a, force);
}
this.translatePositions(a);
}
}
}
And here is the physics object class
/**
* Create a particle object with rendering and physics properties
* @param {Object} configs - configs for the particle
*
*/
export class particle {
constructor(configs = {}) {
//default configs
Object.assign(this, {
type: "particle",
// physics
physics: true,
position: new Vector2(),
velocity: new Vector2(),
acceleration: new Vector2(),
force: new Vector2(),
mass: 10,
//visual
radius: 10,
color: "#ffffff",
});
//apply changes
Object.assign(this, configs);
//used by the grid iterator
this.size = new Vector2(this.radius, this.radius);
}
dispose() {
this.isWaste = true;
}
}
I checked if the problem was arising from the Gravitational Constant being too small but it's not the case.
p.s the Vector 2 class is taken from three.js
CodePudding user response:
Be careful about signs ( /-) and directions. This gives you a vector pointing from b
to a
:
force.subVectors(a.position, b.position);
(b) -----> (a)
Subsequently a force is applied to a
in the direction of that vector:
this.applyForce(a, force);
So that's in the wrong direction because it pushes a
away from b
. Adding a minus sign to the mass "fixes" the problem, because it cancels this error out.
Probably you want to compute the vector from a
to b
instead:
force.subVectors(b.position, a.position);