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?
In symbols, the magnitude of the attractive force F is equal to G (the gravitational constant, a number the size of which depends on the system of units used and which is a universal constant) multiplied by the product of the masses (m1 and m2) and divided by the square of the distance R: F = G(m1m2)/R2.
The usual definition of gravity in different dimension makes it so that if space is 2d, then Newtonian gravity goes as 1/r not 1/r^2 (as David Zaslavsky points out, GR in 2+1 dimensions is even weirder--- gravity doesn't exert long range forces in 2d, but it creates point conical deficits.
If the mass of one of the objects is doubled, then the force of gravity between them is doubled. If the mass of one of the objects is tripled, then the force of gravity between them is tripled. If the mass of both of the objects is doubled, then the force of gravity between them is quadrupled; and so on.
The gravitational force exerted by the celestial bodies at the center increases as their mass increases and decreases as their distance to the revolving body increases. For example, the force of gravity of the Sun on the Earth is much larger than that of the Earth on the moon.
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.
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 );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With