Home > Software design >  Why do the objects in my physics simulator attract each other only when they have a negative mass?
Why do the objects in my physics simulator attract each other only when they have a negative mass?

Time:12-14

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);
  • Related