Search code examples
game-physicsmotion

How to calculate motion of a 2D object propelled by multiple thrusters?


Working on a game with objects made of of connected squares (think of Tetris shapes). Each square can randomly have a thruster pushing it in one direction: up, down, left, right. How can I calculate the total X/Y veloxities and rotation of the object in 2D space?

Edit: added picture to show a few example objects

enter image description here


Solution

  • Simple force applied to an object

    Object has position x,y, rotation r and deltas dx, dy, and dr.

     object { x : 0, y : 0, r : 0, dx : 0, dy : 0, dr : 0, mass : 1000};
    

    Force is at a location x,y and in a direction.

    The force is split into acceleration and angular acceleration components by the amount the force is directed to the center of mass and along the tangent to the center of math. Then divided by the mass for the acceleration and mass * distance from center of mass for angular acceleration. These accelerations are then added to the deltas x,y and r. Those deltas are then used to update the object location and rotation.

    object.x += object.dx;
    object.y += object.dy;
    object.r += object.dr;
    

    As the maths does not work if the force is applied at the center of mass the function checks if close and calls a simpler method that does not include rotation.

    Code is Javascript and more details in the comments.

    // apply force in direction to object at the center of mass
    function applyForceCenter(object, force, direction){ 
        force /= object.mass; 
        object.dx += Math.cos(direction) * force;
        object.dy += Math.sin(direction) * force;
    }
    
    // apply force to object at location in direction 
    // location is absolute
    function applyForce(object, location, force, direction){ 
        // get the relative position of the force to the center of mass (COM)
        var ox = object.x - location.x;
        var oy =  object.y - location.y;
        var radius = Math.sqrt(ox * ox + oy * oy); // get distance from COM
        if(radius <= 1e-6){  // if too close use simple calcs
            applyForceCenter(object,force,direction);
            return;
        }
        // get the angle from the applied force to the center
        var toCenter = Math.atan2(oy, ox); // Yes y is first
        // the difference between the direction of force and direction to center
        var pheta = toCenter - direction;
        // reduce force by mass
        // Get the component parts of the force
        var Fv = Math.cos(pheta) * force; // The amount of the force that
                                          // contributes to acceleration
                                          // along the line to the center
        var Fr = Math.sin(pheta) * force; // The amount of the force that
                                          // contributes to angular acceleration
                                          // along the tangent from the center
        // Reduce acceleration by mass 
        Fv /= object.mass;
        // get the x,y components of that force along the line from where
        // it is applied to the center of mass
        object.dx += Math.cos(toCenter) * Fv;
        object.dy += Math.sin(toCenter) * Fv;
    
        // reduce angular acceleration by distance and mass
        Fr /= (radius  * object.mass);                                        
        object.dr += Fr; // add the change of rtoation
    
    }