Orbit Mechanics

OrbitSketch.jpgMonths ago, around the start of DuskLight Studios, I wanted to create a game about flying around planets in orbit with each other. A game about exploration through space, adjusting your own orbit to move from planet to planet. I severely underestimated the difficulty of this.

Elliptic path

Orbit1Small.png

My first experiment in Unity included a single planet with a moon in orbit. The moon’s velocity was affected by the planet’s gravity, which varies in strength depending on distance to the planet. I couldn’t figure out the mathmatical formule to calculate the gravity’s pull, trying out faulty code I found online. It did result in an orbit, but it wasn’t right.

When a ship orbits a planet (and only that planet), it should be locked in an elliptic path. As long as it doesn’t accelerate in any direction, the ship will end up in the exact same position as it started at and eternally follow the exact same path. The first experiment did not achieve this, and I moved on to other projects to prevent wasting too much time.

Gravitational pull

A couple of weeks ago, I gave it another shot. I found a quite interesting link providing me with several different solutions to orbital mechanics in code.

SimpleOrbit.gif
A simple orbit

The Euler integration was easy to implement into a new Unity project. It started off in script; using the transform’s position, a velocity vector, and the gravitational pull to mimick the results. It worked, allowing me to iterate and improve upon the code.

Gravitational pull (g) equals to planet mass (m) multiplied by the square of distance between planet and ship (d^2): g = m * d^2

The function (present within the planet’s script) I currently use to calculate the gravitational acceleration:

public Vector3 GetGravity(Vector3 attract) {
        Vector2 delta = transform.position – attract;
        Return delta.normalized * ((mass * gravityConstant) / delta.sqrMagnitude);
}

Vector3 attract is the position at which the orbitting object is located.

Note that the calculations occur with Vector2 instead of Vector3, and that the square magnitude is used instead of the regular magnitude, both saving performance. Calculation of the square root of any number is much more CPU intensive than multiplications. Same goes for the Mathf.Pow(x) function.

Unity Physics

Achieving orbit is great and all, but I needed the code to work with the built-in Unity physics. That way I could include realistic collisions with planets and asteroids. I quickly ran into a couple of weird problems, though.

Note that all calculations should be run within the FixedUpdate, so it runs in sync with the Unity physics simulation.

I had to remove my own velocity vector and start using the Rigidbody2D’s velocity instead. Normally you’d use the function body.AddForce(gravity) to accelerate the ship, which I did at first. This resulted in a steady but weird orbit that didn’t follow the elliptic path as it should, leading me to believe that using forces for gravity is a bad idea. There was no way to really know how much velocity would be gained if I added a certain amount of force. Add to this that gravity pulls all objects equally, regardless of object mass, it proved I needed a different solution.

Instead of forces, I decided to affect the velocity directly. (body is the Rigidbody2D)

gravity = planet.GetGravity(transform.position);
velocity = body.velocity;
velocity += gravity * Time.fixedDeltaTime;
body.velocity = velocity;

CentreOfMassOrbit.gif
Defying laws of physics

This resulted in an almost perfect elliptic orbit, but the ellipse was a little off. It kept decreasing or increasing in size in a pattern. The issue here was the centre of mass of the rigidbody.

The centre of mass is automatically calculated by Unity, using the size and locations of the 2D colliders attached to the rigidbody. Changing the centre of mass to Vector3.zero solved the problem, but I also changed the gravity position to the centre of mass. If I ever change the centre of mass again, it should still work.
.

gravity = planet.GetGravity(body.worldCentreOfMass);

Asteroids.gif
Collisions

Now I can look happily at my near perfect elliptic orbit, watching my ship bump into asteroids and settle in a new orbit, occasionally crash landing on the planet itself and coming to a halt.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s