9

I want to simulate Newton's law of universal gravitation using Box2D.

I went through the manual but couldn't find a way to do this.

Basically what I want to do is place several objects in space (zero gravity) and simulate the movement.

Any tips?

jscs
  • 63,694
  • 13
  • 151
  • 195
Ashika Umanga Umagiliya
  • 8,988
  • 28
  • 102
  • 185

3 Answers3

18

It's pretty easy to implement:

for ( int i = 0; i < numBodies; i++ ) {

    b2Body* bi = bodies[i];
    b2Vec2 pi = bi->GetWorldCenter();
    float mi = bi->GetMass();

    for ( int k = i; k < numBodies; k++ ) {

        b2Body* bk = bodies[k];
        b2Vec2 pk = bk->GetWorldCenter();
        float mk = bk->GetMass();

        b2Vec2 delta = pk - pi;
        float r = delta.Length();
        float force = G * mi * mk / (r*r);

        delta.Normalize();
        bi->ApplyForce(  force * delta, pi );
        bk->ApplyForce( -force * delta, pk );
    }
}
iforce2d
  • 8,194
  • 3
  • 29
  • 40
  • 1
    For those who don't know, G = [gravitational constant](http://en.wikipedia.org/wiki/Gravitational_constant) = 6.67×10 ^−11 N·(m/kg)^2. It is a universal constant (not Earth's g=9.8 m^2/s^2). – GKFX Jul 23 '14 at 16:36
  • Hey, just for reference, the [Wikipedia page on Orbit](https://en.wikipedia.org/wiki/Orbit#History) has some valueable info. For example, you can find the orbit center of two objects that are following the universal gravitational laws: It's their common center of mass. Also, a small check on the formulas can help you decide a initial velocity for both bodies to make them orbit each other with no collisions. – Gustavo Maciel Jul 26 '15 at 05:12
1

As said by others, Box2D has no buildin support for it. But you can add support for it to the library in b2_islands.cpp. Just replace

v += h * b->m_invMass * (b->m_gravityScale * b->m_mass * gravity + b->m_force);  

with

int planet_x = 0;
int planet_y = 0;
b2Vec2 gravityVector = (b2Vec2(planet_x, planet_y) - b->GetPosition());    
gravityVector.Normalize();    
gravityVector.x = gravityVector.x * 10.0f;    
gravityVector.y = gravityVector.y * 10.0f;    
v += h * b->m_invMass * (b->m_gravityScale * b->m_mass * gravityVector + b->m_force);    

Thats a simple solution if you have only one planet. If you want less force the further away you are, you could use 1/gravityVector instead of normalizing it. That would also make it possible to add up the gravity of to planets. The you could also iterate over a planet list and sum the gravityVectors up.

Additionally implementing a function like b2World::CreatePlanet might be usefull then.

The 10.0f are just an approximation of the 9.81f from earth, you might need to adjust it. If the mass of the planet is relevant you might need a constant to be multiplied with it, to make it look more realistic, or just increase the density of the object to make it match the real weight of a planet.

Sure you can also set the gravity to 0, 0 and then calculate it before each step for every object, but that might not have so much performance.

cpdef
  • 11
  • 1
1

Unfortunately, Box2D doesn't have native support for it, but you can implement it yourself: Box2D and radial gravity code

Gustavo Maciel
  • 652
  • 7
  • 20
Michał Kuliński
  • 1,928
  • 3
  • 27
  • 51