Entry#3: Gravity

Being Project Planets a space exploration game, gravity has an important role in the gameplay. It needs to be strong enough to actually have an impact on the ship, but not too strong that it becomes frustrating for players becoming unable to control their ship anymore. There is also the problem of balancing between strong gravity wells (stars and black holes), and weak gravity wells (planets and moons).

The first thing that I noticed is that a realistic gravity formula wouldn’t work. Using the inverse of the distance squared makes the gravity too weak at medium to long distances while becoming way too strong at shot distances. After playing with different formulas I decided for the custom curve (that is similar to an hyperbole) that can be seen in the picture below.

Image 1: Gravity curve

This curve alone wouldn’t work, it needs a few other components to do its job as intended. Each gravity well has a circle collider of a set radius. Outside the collider other objects are not affected by the gravity well’s gravity. Inside the collider objects are affected depending on the distance from the well (distance is calculated from the surface of the well, not the center). The distance is normalized between the surface of the well and the edge of the gravity range, the value obtained is then used to evaluate the previous curve (Image 1). Each gravity well has a maximum and a minimum gravity value. A curve value of 0 equals the minimum value, a curve value of 1 equals the maximum value, other values are interpolated.

Vector2 direction = transform.position - gravityObject.transform.position;

float distance = direction.magnitude - _coreSize;

float coeff = distance / _gravityRadius;

float forceMagnitude = _gravityForceBounds.x + (_gravityCurve.Evaluate(coeff) * (_gravityForceBounds.y - _gravityForceBounds.x));

gravityObject.ApplyGravity(this, direction.normalized * Mathf.Clamp(forceMagnitude, _gravityForceBounds.x, _gravityForceBounds.y));

This code excerpt shows how this is applied.
_coreSize is the radius of the gravity well (i.e. the radius of the planet).
_gravityRadius is the distance between the surface of the gravity well (i.e. the surface of the planet) and the edge of the gravity collider.
_gravityForceBounds is a Vector2 where the X value is the minimum gravity value and Y is the maximum gravity value.


This allows me the flexibility to calibrate each gravity well as I need. Normally the highest value for the gravity force is exactly at the surface of the gravity well, but by increasing the _coreSize I can create a ring around the gravity well that has the maximum value for the gravity force.
The curve can be customized as well to create different gravity wells, even with weird behaviors if needed.

Some of you may have noticed that the gravity is applied as a force, regardless of the affected object mass. This is not how gravity works in real life but this helps me achieve a behavior that it is more fun in my opinion. Lighter objects are affected more from gravity than heavier ones. This means that physical bullets are affected more than a spaceship. If a ship is in stable orbit around a planet and starts firing with a physical weapon (more on weapons later on in the devlog) bullets are going to fall towards the gravity well.

Image2: Gravity comparison

In the image above we can see in red the trajectory that the ship in orbit is following (more or less), and we can see the bullets (the orange dots) that, even if they are faster than the ship, they start falling towards the star instead of going to a bigger orbit (as it would happen in the real world).
This makes fighting against enemies when close to a gravity well trickier as gravity should be taken into consideration when aiming (unless an energy weapon is used but, again, more about this later on).

Some of you may remember that in the previous entry we discussed about a counterforce applied to the ship to limit the maximum speed that it can achieve. But the gravity code does not feature any of this. By using gravity a ship can theoretically accelerate above its maximum speed because that’s the maximum speed that its thrusters can achieve, not an hard limit per se. This also explains why the counterforce has a cap equal to the force exerted by the thrusters. If this weren’t the case we would have the absurd case where by engaging the thrusters the ship would decelerate (if the ship is currently above the max speed).
This makes navigating through strong gravity wells even more challenging for the player and can lead to fun and original areas to explore.

This concludes this initial analysis on the gravity of the game.