Gravity Engine Doc (1.6)

New in 1.6 (Submitted for Review):

Maneuvers: Maneuvers that will be executed at specific times for specific NBodies can be registered with the Gravity Engine. These maneuvers can be created by the game designer or determined by code that calculates how to match another objects trajectory or code that computes orbit transfers.

Trajectory Interception: Intersection points for future trajectories can be detected. The maneuver required to match the intersected trajectory can be determined.

Orbital Transfers: In scenarios with a central mass, orbit maneuvers can be calculated to transfer to a desired orbit. In release 1.6 only transfers between circular orbits in the same plane are implemented (Hohmann and Bi-Elliptic). Out of plane transfers will be provided in the next release. See the mini-game.

Rocket Engines: Continuous thrust rocket engines are now fully integrated into the physics engine. A uniform thrust is applied on every dt slice. The implementation also allows the trajectory of powered flight to be predicted and shown in the scene. Rocket engines only apply to massless bodies (in the context of planets and moons, spaceships are massless to a good approximation). The mass of the spaceship is used in determining the acceleration due to the thrust of the engine. See the mini-game.

Bug fixes/minor enhancements:

  1. NBody object rotation to follow trajectory of the orbit (NBody Inspector now has a “Rotate frame in Orbit” checkbox).
  2. Remove number of points parameter in trajectory component. This is now determined by the Gravity Engine trajectory time setting and the trajectory minimum distance between points attribute.
  3. Re-structure interleaving of massive, massless and kepler evolution to fix issues with stability of time zoom. (Created a stand-alone TimeZoom script).
  4. Changed trajectory re-computation parameter in GravityEngine to specify the number of trajectory re-computations per frame.

Code Documentation:


Gravity Engine (GE) provides a powerful, accurate physics engine to simulate gravity including:

  • Double-precision simulation of masses and particles using force calculations and optional (per-body) use of two-body Kepler evolution
  • Creation of orbits with control of shape, inclination and orientation.
  • Solar system model for ANY planet, comet or asteroid
  • Gravitational collisions with particle ejection effects
  • Simple spaceship example that allows accurate movement under gravity with projected trajectory
  • A library of over 50 three body solutions with special purpose algorithms to allow simulation through near-misses
  • Centralized control of simulation units (km, AU, arbitrary), overall evolution speed, distance and mass scales

It is not necessary to understand the details of the gravitational physics. Gravity can be added to a scene without scripting.

Code Documentation:




Units – Earth Orbit

Build the Solar System

Binary Stars




Orbit Prediction

Tutorials are also available from the Title bar in a drop down from Gravity Engine 1.3 and the NBodyPhysics YouTube channel:

Package Overview

Fundamental Classes

There are three key classes involved in adding gravitational evolution of objects to your Unity project:

  1. GravityEngine – the script that performs all the physics calculations and updates object positions in the scene.
  2. NBody – a script attached to all bodies to be controlled by the GravityEngine. Used to specify their mass and initial velocity.
  3. GravityParticles – added to a particle system to allow it to be evolved by the GravityEngine

The GravityEngine is a very flexible physics engine that provides:

  • Choice of dimensionless or real-world units for distance, mass and time
  • Ability to scale chosen units to achieve the desired game “feel”
  • Advance options to select:
    • Physics algorithm
    • Time steps per frame for algorithms
    • Performance optimizations for gravitational particles
    • Options to allow objects to be detected automatically or added via scripts

NBody Orbit Scripts

Finding the exact initial velocity that creates a specific orbit can be challenging, requiring either physics calculations or trial and error. To eliminate the need for this there are a number of scripts that can be used in addition to the NBody script to control the initial conditions of a body to create a specific orbit.

These scripts will show the path of the orbit in the scene view as the objects are added.


There are several options for adding initial conditions or constraining the motion of an NBody object:

  • OrbitEllipse – start a body in a specified elliptical orbit around another body. The body can be moved using gravitational force, or it can move in a fixed path using Kepler’s Equation.
  • OrbitHyperbola – set the velocity to achieve a specfic hyperbolic orbit
  • Binary Pair – initialize a pair of NBody objects so that they form a binary pair with specified orbits. Based on interactions with other bodies the actual orbit followed may change.
  • FixedObject – object does not move, however it’s mass will influence other objects in the scene

Gravitational Particles

GravityEngine allows particle systems to move based on the gravitational field. Particles are treated as massless bodies and are subject to the gravity of NBody objects in the scene. An existing particle system can be placed under the control of the GravityEngine by adding a GravityParticles script.


The GravityParticles script can also have an optional delegate that controls the initialization of the particles. Several delegates are provided:

  • DustBall – a spherical shell of particles moving at a specified initial velocity
  • DustBox – a 3D rectangle of dust with individual control over size in (X,Y,Z)
  • DustRing – a ring of particles that orbit around a massive NBody parent. The orbit parameters can be controlled. Useful for effects like planetary rings.


Collisions between NBody objects are detected using Unity colliders. Since these collisions are due to gravitational interactions, the NBodyCollision class handles updates to the physics. The collision can be handled in one of three ways:

  1. Absorb
  2. Bounce
  3. Explode
  4. Explode or Bounce (based on contact velocity)

In each case the physics engine is updated as required and momentum and energy are conserved.

 Tutorial Scenes

OverviewCentral star with an orbiting planet and particle ring.
T1 Binary PairCreate a binary pair of stars that orbit their center of mass.
T2 OrbitsCreate elliptical and hyperbolic orbits. Demonstrate N-body vs Kepler evolution
T3 CollisionsDemonstrate the ways collisions can be handled in Gravity Engine.
T4 ParticlesSetup particle systems (box, orbiting ring)
T5 Orbit PredictionTwo body orbit prediction with the OrbitPredictor component.
T6 Trajectory PredictionFull N-body look-ahead modelling of trajectories with time markers.
Units - Earth OrbitSpaceship and space station in low Earth orbit with units in km.
Solar System InnerShow how to create the inner solar system in AU units.

Demo Scenes

3BTrajectoryThree body solutions with a spaceship and trajectory prediction.
AddDeleteTestInteractive add/delete of massive, massless and Kepler orbiting bodies.
ForceCustomDemonstrates a custom (non-gravity) central force and its effect on planets and particles.
Force Inverse RShows a 1/R (vs gravity's 1/R^2) force.
FrameRateTestAutomatically add massive bodies until the frame rate drops to 58 FPS. Reports N.
OrbitDecayShows how a simple add on script can create decaying orbits.
RandomPlanetsScene which auto-creates a series of planets in random orbits.
SolarSystem InnerModel of inner solar system
Solar System OuterModel of outer solar system.
ThreeBodiesShows the three body configuration generator.


Gravitational Objects



GravityEngine is the primary class in the asset. For gravitational motion the scene must contain an object with a GravityEngine component. This can be added via the Unity Menus (GameObject/3D Object) or by adding the GravityEngine script to an existing object in a scene.

GravityEngine evolves objects that have an NBody script attached. NBody defines the mass and initial velocity. The GravityEngine can automatically detect all NBody objects in a scene when it starts (the default), be given an explicit list of objects, or objects can be added by script calls to GravityEngine.AddBody().

The engine operates on the FixedUpdate() cycle to ensure that physics evolution tracks game time. In some cases the exact amount of evolution in a specific cycle will vary slightly depending on whether the evolution algorithm has run ahead or behind on previous cycles.

In general the GravityEngine attributes cannot be changed while the scene is running (with the exception of the timescale attribute).

The inspector view shows the key parameters:




Gravity Engine allows a choice of units in the game positions. In gravity force calculations it is convenient/efficient to set the force constant G=1.

The follow unit choices are supported:

  1. DIMENSIONLESS: Arbitrary units used directly in the force calculations. When selected the inpector allows Mass Scale and Time Scale to be varied.
  2. SI: Units are in m/kg/sec. See Real-Unit scaling below.
  3. ORBITAL: Units are km/1E24 kg/hours. See Real-Unit scaling below.
  4. SOLAR: Units are AU/1E24 kg/years. See Real-Unit scaling below.

Mass Scale

The GravityEngine allows for the changing of mass scale of all NBody objects in the scene with a single parameter. Initial velocities of NBody objects will also be scaled such that paths taken by the bodies will not change when mass scale is altered.

Adjusting mass scale can be a useful way to change the speed at which things happen in the scene. As the mass scale increases, forces between the bodies increase and the evolution in the scene happens faster. This is the most common technique for adjusting the overall speed of the evolution in the scene.

Mass scale adjustments do not affect the amount of CPU time used in gravitational evolution.

To delve further, see the section Scaling below.


The timescale controls the ratio of time in “the physics world” as compared to time in the game. It can be used to control the overall speed but this happens in a way that affects the CPU time used for gravitational evolution. A timescale value larger than 1 performs more calculations per cycle. A timescale value of less than one will result in fewer calculations per cycle. In either case the evolution calculations will have the same accuracy.

Real-Unit Scaling

When using non-DIMENSIONLESS units the inspector allows a choice of Unity units per distance unit (e.g. Unity units per km). Changing this scale will automatically adjust the distances between all objects in the scene.

Time scale is also adjustable for non-DIMENSIONLESS units (e.g. game sec. per hour). This change, combined with the length scale and use of G=1 in the force equation results in the internal calculation of a mass scale that ensures the correct evolution in the scene.


Trajectory prediction control in the Gravity Engine component works in tandem with Trajectory components added to NBody objects in the scene. Instructions for the configuration of these is provided in more detail BELOW(link) and in Tutorial 6(link).

Trajectory Prediction (Checkbox)

If enabled, the GE will simulate the future progress of all massive and massless bodies in the scene for the time indicated by “Trajectory Time”. NBody objects that have a child with a Trajectory component will have the future path rendered via their Line Renderer components.

If there is a call to ApplyImpulse or ResetTrajectory then the future evolution will be re-computed.

Trajectory Time

The time into the future that all objects will be evolved for to determine trajectories for those objects with Trajectory components.

Frames Between Resets

The number of frames that must elapse before a new ResetTrajectory (directly or via ApplyImpulse) can be performed. Since a trajectory re-computation requires the scene be evolved for the time indicated by “Trajectory Time” this can be a CPU intensive activity. Imposing a non-zero limit ensures that this does not occur too often.

Canvas for Text

The Trajectory component can optionally add labels to indicate the future time along the trajectory. These text components require a World View Canvas in the scene. This field provides the reference to the Canvas for use by the Trajectory components.




There are a number of possible algorithms for gravitational evolution. They vary in accuracy and computational complexity.

  1. Leapfrog: The best default choice. This is a computationally cheap algorithm with a fixed time step that conserves energy well.
  2. Hermite: A variable time-step algorithm that will spend more CPU cycles when objects get close to improve accuracy.
  3. AZTTriple: A special case algorithm for ONLY three bodies. It is a “regularizing integrator” that allows objects to get infinitely close without numerical instability. Typically used in conjunction with the ThreeBodySolution class.


The force chooser allows control over the force law used in the engine. The default choice is standard gravity (Newton’s force law). Other choices are described in the force modification section.

Optimize Massless Bodies

NBody objects with a mass of zero (massless) are influenced by other bodies’ mass but do not affect others. The GravityEngine detects this and massless bodies are evolved separately using a Leapfrog algorithm. This reduces the CPU cost of evolving massless bodies since the interactions between them are skipped.

If there is a need to use the Hermite algorithm for massless bodies then this toggle can be cleared and no massless optimization will occur.

Automatically Add Nbodies

When selected the GravityEngine will examine all objects in the scene (during the Awake phase) and take control of the evolution of those bodies that have an NBody or GravityParticles component.

In cases where this behavior is not desired (e.g. a player spaceship is not moved while the rest of a solar system is) this option can be unselected. In this case the inspector will show a new section to list the bodies that should initially controlled. Existing scene objects with an NBody component can be dragged onto the Bodies list.

In both cases additional bodies can be added via calling GravityEngine.AddBody() and particles systems via GravityEngine.RegisterParticles()

Evolve At Start

By default the GravityEngine will begin evolving all the NBody/GravityParticles objects in the scene when the system starts. Clearing this checkbox can disable this. When cleared, evolution will start when GravityEngine.SetEvolve (true) is called.

Physics to World Scale

A scale factor used to adjust the distance scale used in the physics engine to the Unity positions in the scene. Physics positions are determined by dividing their Unity positions by this factor.

For example, if two bodies are 10 units apart and the physics to world scale is 1 the GravityEngine will use 10 as the distance between bodies. In some initial conditions from the scientific literature the distance scale defined in may be in a very small range, typically (-1..1). It is easier to use these values in the physics calculations because it avoids the need to scale masses and velocities. In this case, setting the physics to world scale to 10 and then positioning the bodies 10 units apart will result in them being scaled down by 10 in the physics calculations and the physics algorithm will see them as 1 unit apart.

This parameter is used by the the ThreeBodySolution code to allow three body physics that is specified in the range of [-1,1] to be displayed using a larger scale in a Unity scene.

Physics Steps Per Frame

This parameter defines the approximate number of times per frame the physics engine will re-calculate positions for NBody objects. A larger number will result in more accurate physics at the cost of more CPU effort. Default value is 8.

Physics (Particles) Steps Per Frame

This parameter defines the approximate number of times per frame the physics engine will re-calculate positions for particles. A larger number will result in more accurate physics at the cost of more CPU effort. Default value is 2.


The GravityEngine evolves objects with an NBody script attached to them.

The inspector view for a general NBody object depends on the choice of units. For DIMENSIONLESS units it is:

For a scene with real-world units it is:


Mass is specified in dimensionless units. A value of less than zero will be set to zero.

Initial Pos

In those cases the object position is set by the transform component in the usual manner. When real-world units are used the position in real-world units is specified here and the objects position in the scene is calculated based on the length scale specified in the GravityEngine component.

This field is not used in dimensionless units.


A Vector3D specifying the initial velocity of the Nbody. If the initial conditions are controlled by an additional component (e.g OrbitEllipse) this field may not appear. The inspector view for an object that has another component providing initial conditions for motions (i.e. an OrbitEllipse or BinaryPair component) will look like:

In this case the initial velocity is determined by another component.

Automatic Particle Capture Size/Particle Capture Radius

If automatic capture size is selected, the particle capture size will be taken from the scale of a child object containing a MeshFilter object. This corresponds to typical use of NBody objects in which a child is a 3D Sphere. This ensures the particle capture size matches the sphere.

Any particle that enters the capture radius of an NBody will be inactivated.

If the automatic checkbox is cleared, a value for capture radius is required.


An Orbit around another object can be initialized with the OrbitEllipse component. This script must be attached to a game object containing a NBody component. Typically, the object around which this NBody object is to orbit is the parent. For example:


Selecting an OrbitEllipse object or the parent object will show the ellipse in the scene view.For a brief summary of orbit parameters see Lakdawalla’s Blog. Adjusting these parameters and seeing the result is the best way to gain insight into their role.  In cases where the inclination is zero, Ω and will do the same thing.

The inspector view of this component is:


Evolve Mode

There are two modes in which OrbitEllipse operates:

GRAVITY_ENGINE mode will initialize the velocity of the NBody to launch it on the specified orbit. Forces from other bodies may affect the NBody and affect its path. Changes made to the body via GravityEngine.ApplyImpule() will change the path the object takes. This is the mode that is used when correct physics is important.

KEPLERS_EQN mode will force the planet to follow the specified orbital path. The mass of the NBody will affect other bodies but they will not affect it. This mode is used when deterministic motion is required (at the cost of physical accuracy). It can also be useful in large orbital systems – since Kepler’s equation uses less CPU than calculating all the forces between bodies in a large orbital system.

Center Object

Displays the name of the object around which this body will orbit. This is detected automatically if the object is the child of another NBody object. It can also be set explicitly to any object in the scene with an NBody component.

Parameter Choice

Selects whether the size is specified as semi-major axis (a) or distance of closest approach (p).

Pericenter/Semi-Major Axis/Eccentricity/Ω/i/

  1. Size: specified by either the semi-major axis (a) or the point of closest approach, the periapse (p).
  2. Shape: Controlled by eccentricity in the range 0 to 1. A circle has e=0, an infinitely thin ellipse has e=1. GravityEngine will limit e to a maximum of 0.99
  3. Orientation: Celestial mechanics uses a specific choice of Euler angles defined as follows:
    1. Ω (longitude of the ascending node)
    2. Angle of inclination
    3. (angle from ascending node to pericenter)

Experimenting with orientation parameters in the scene view and observing the changes in the ellipse is the best way to understand these parameters. (The ascending node is the point where the object moves through the reference (x,y) plane in the +Z direction. The “line of nodes” is the line where the ellipse crosses the reference plane, assuming the inclination is non-zero. See the Wikipedia page on Orbital Elements.)

Starting Phase

Defines the objects initial position on the ellipse in degress (0..360).


Initializes a hyperbola path around a central object. This script must be attached to a game object with an NBody component. When selected the path of the orbit will appear in the scene view.


Hyperbolic orbits by definition have an eccentricity > 1.


Pericenter/Semi-Major Axis/Eccentricity/Ω/i/

The same as OrbitEllipse, with the requirement that eccentricity be greater that 1.

Initial Distance

Sets the initial distance from the center object where the orbit evolution will being. By default this will be on the inbound portion of the hyperbola.

Initial Distance Outbound

When set, indicates that the initial distance should be used to position the body on the outbound leg of the hyperbola.



The OrbitRenderer component works in conjunction with a LineRenderer to show the predicted orbit path in the scene view during game play. The script must be attached to an object with an OrbitEllipse or OrbitHyper component – from which the orbit path will be determined at the time the scene starts.

A body may not exactly follow this path if there are interactions with other masses. The OrbitRenderer is attached to a game object that is a child of the NBody to allow for separate material selection.

To see the orbit, the Line Renderer component must be correctly configured (i.e. add a suitable material)

A prefab “OrbitPath” is provided.


The OrbitPredictor script predicts the orbital path a body will take given the current velocity of the body and draws the path using a LineRenderer. The projected orbital path updates on each FixedUpdate() cycle – so the influence of user provided velocity changes or changes due to interactions with masses other than the central body will be reflected in the updated path.

Orbit prediction is done using a two-body calculation, transforming the position and velocity with respect to the center body into orbital parameters. The predicted orbit will be accurate if the center body is the dominant source of gravity. If there are other significant sources of gravity in the scene the prediction will not be accurate. [Solving the general orbit prediction problem is not mathematically possible in most cases and would require a simulation of the future evolution of the system – which is impractical].

Screen Shot 2016-08-23 at 6.33.33 AM.png

CenterBody: The NBody containing object around which the orbit should be calculated.

Body: The body for which the orbit will be calculated.

Number of Points: The number of points to use in the line renderer to represent the orbit.

Adding an OrbitPredictor component will automatically add a LineRenderer component. To see the orbit, the Line Renderer component must be correctly configured (i.e. add a suitable material)

Screen Shot 2016-08-23 at 6.35.55 AM.png

The orbit predictor script adds an OrbitEllipse and a OrbitHyper component to the object on which it resides. It instantiates a helper class OrbitData that determines the orbit parameters based on the velocity of the object and the center object. The eccentricity resulting from this calculation is used to activate the elliptical or hyperbolic orbit display as appropriate. In the case of elliptical orbits the OrbitData class also determines the time to closest approach (the variable tau).


The TimeZoom script allows the keys 1-5 to adjust the run-time evolution of the GravityEngine via the GravityEngine SetTimeZoom() method.

Run-time time control is done by increasing the number of integrations done in each fixed update cycle, so very large values when used in scenes with many objects may use significant CPU.

The base time rate in the scene can be controlled via the Scaling foldout of the Gravity Engine class.


The Trajectory component shows the future path of an NBody object based on a simulation of the entire scene projected into the future. It handles cases where there are multiple massive objects interacting. It is more computationally intensive that an OrbitPredictor – which uses a two-body model of the interaction.

The Trajectory component works in conjunction with Trajectory configuration options in the Gravity Engine. It is attached to a *child* of an NBody object – since it requires a Line Renderer and material. Adding a Trajectory component will automatically add a Line Renderer component. In order to see the line in the scene a suitable material must also be added to the object.

The parameters for a Trajectory are:

Min Vertex Distance

Minimum distance between positions required before a new point is added to the Line Renderer.

Max Points

Maximum number of points to be added to the Line Renderer.

Time Marker Prefab

A trajectory may optionally add an object at fixed time intervals along the trajectory. This element provides the prefab used. The objects added will be oriented so that the z-axis of the object is aligned with the path of the trajectory.

Time Mark Interval

The interval between time markers on the trajectory.

Time Text Prefab

A time label can be added to the time markers. This requires a prefab object containing a UI Text component. In addition the Canvas field in the Gravity Engine Trajectory configuration must be configured with a Canvas that has mode World View.

Align Text to Traj.

If checked the z-axis of the Text prefab will be aligned with the Trajectory.


This script provides a simple per-frame reduction in velocity and results in the decay of an object in orbit.

Binary Pair

Binary star systems are very common. Configuring a pair of objects in a specific orbit around the center of mass can require careful calculation of the initial velocities. The BinaryPair component handles this task and provides a scene view of the resulting orbits.


The BinaryPair component is added to a top-level game object and two “stars” are added as children. These stars each have an NBody component that describes their mass. By selecting the BinaryPair object in the scene view the orbits of the objects will be displayed and can be adjusted. GravityEngine provides a binary pair as a prefab object.



Specifies the velocity of the center of mass of BinaryPair.

Ellipse Parameters

See the description of fields in OrbitEllipse above.


Adding a FixedObject component to an NBody game object creates an NBody object that has a mass but remains at a fixed position.

Gravitational Particles

Gravity Particles

Adding a GravityParticles component to a Unity particle system will allow the GravityEngine to move the particles according to the gravity of all objects in the scene. The particles will be treated as massless bodies and evolved using a Leapfrog algorithm.

Particle creation can be done by the Unity particle system component or can be over-ridden by adding a component that implements the IGravityParticlesInit interface (scripts DustBall, DustBox and DustRing demonstrate how this is used).

The particle system must operate in World Space. This particle system attribute will be changed automatically (and a Warning issued) if it is set to local.

Scenes with large numbers of GravityParticles can require more from the CPU. Care must be taken when adding large numbers of particles to ensure game performance is still acceptable. Reducing the steps per frame for Particles in the GravityEngine may also be useful.


Initial Velocity

The initial velocity to be added to all particles from the particle system on creation. This option only appears if there is no init script attached to the component.

Dust Ball

DustBall implements IGravityParticlesInit and is used to initialize a sphere of particles all moving at the same velocity.



Initial velocity of the particles in the dust ball.


Radius of the dust ball.

Dust Ring

This script initializes a ring of particles around an NBody object.

The shape and orientation of the ring are controlled in the same way as an OrbitEllipse object.


Ellipse Parameters

See the description under OrbitEllipse, above.


Defines the width of the particle ring as a percentage of the radius.

Dust Box

Initializes particles in a 3D box.



Size of the X, Y and Z axes of the box. Box will be centered at the transform position.


Initial velocity of dust particles


3D rotation of the dust box. (Rotation must be controlled here and not in the game object transform to ensure correct rendering by the GravityEngine).


ExplosionFromNBody creates a cone of particles that ‘explode’ away from an NBody object. It determines the required velocity to escape the gravitational field of the NBody such the particles reach a specified distance from the body.


Explosion Size/Velocity Adjust

The maximum distance the explosion particles should travel before falling back to the NBody on which the explosion is occurring.

The size is used to determine the initial velocity of the explosion. In cases where there is a large initial velocity due to a massive NBody or small radius, the first integration step may move the particles too far. This will result in the size being exceeded. The Velocity Adjust field can be used to “tune down” the initial velocity. Typically values in the range of 0.7-0.9 are useful.

Cone Width

Defines the width of the ejection cone in degrees (from center axis to outside).

Velocity Spread

The variation in the velocity applied to the particles. The value used in the standard deviation around the velocity required to obtain the indicated size. A value of 0 will ensure all particles start at the same speed, larger values will give a wider range of velocities resulting in a more spread out value.

This component is usually triggered by a collision between NBody objects.

Spaceship Maneuvers: Trajectory Intercepts and Orbit Transfers


Maneuvering a spaceship requires a series of course corrections scheduled to occur at precise future times in the game. To ensure the maneuvers are executed at as precise a physical time as possible, these are scheduled with the gravity engine. Maneuvers are executed by the engine at a time as close to the scheduled time as possible within the limits of the time step in use by the integrator.

A maneuver is specified by the Maneuver class.  The key public values of a Maneuver are:

  • nbody: the body the maneuver is to be applied to
  • worldTime: The future GE world time at which the maneuver is to be executed
  • mtype: (enum vector, scalar, circularize) the type of maneuver:
    • vector: apply the velChange vector to the NBody
    • scalar: apply a velocity change of dV in the current direction of the Nbody
    • circularize: circularize the orbit of the NBody with respect to a central mass

The maneuver specifies a velocity change that is to occur at the maneuver time. A maneuver is added to the GravityEngine via the Gravity Engine AddManeuver() method. [There are also methods RemoveManeuver() and GetManeuvers()].

Commonly, maneuvers are set by code that has found a trajectory interception or an orbit transfer. Examples of both can be found in the UserInterfaceRV script used in the OrbitXfer Scene in Demos/MiniGames.

Trajectory Intercepts

If more than one object in a scene has a Trajectory component then GravityEngine can assess whether these trajectories will intersect at some future point. If there is such an intersection then there are components that can determine the required maneuver to make the first trajectory match the second trajectory from that point on. Note that in order for there to be a rendezvous, the trajectories must intercept at the same time world time. The trajectory intercept can determine both rendezvous and path crossing intercepts.

In order to determine a precise intercept maneuver the trajectory component attached to the objects must record data as their future path is calculated. The RecordData field in their Trajectory component must be set to true. This causes the position at each future frame to be recorded.

The TrajectoryIntercepts class (Scripts/Orbits/Transfers) makes use of this trajectory data to check for an intercept that meets the precision requirements set by the caller. A typical intercept determination is the MarkIntercepts method in the UserInterfaceRV script:

	/// Mark intercepts with the designated symbols and return a list of intercepts found
	/// for the predicted path of ship intersecting with the path of the target.
	private List MarkIntercepts(SpaceshipRV ship, SpaceshipRV target) {
                const float deltaDistance = 1f;
                const float deltaTime = 2f;
                const float rendezvousDT= 1f; 
		trajIntercepts.spaceship = ship.GetTrajectory(); = target.GetTrajectory();
		trajIntercepts.ComputeAndMarkIntercepts(deltaDistance, deltaTime, rendezvousDT);
		intercepts = trajIntercepts.GetIntercepts();
		return intercepts;

The above code uses ComputeAndMarkIntercepts() to determine if the two trajectories come within the specified distance and time of each other. The trajectory comparison checks for points that are within a specified distance from each other. Depending on the speed of the objects there may be many points that meet the intercept criteria. The parameter deltaTime is used to indicate over what time scale common intercept points should be considered duplicates. Finally the rendezvousDT parameter indicates the time precision required to declare the intercept a rendezvous (both arrived at the same time) versus a path crossing.

The TrajectoryIntercepts class creates a marker object at the position of the intercept, making it more visible in the scene. Prefabs must be provided for these markers.

Orbit Transfers

Orbit transfers assume that the spaceship is maneuvering in an environment with a single mass dominating the gravity in the scene. Orbit transfer calculations are done with respect to this central mass.

An orbit transfer is a series of maneuvers calculated to change the current orbit of an object to a desired orbit. This typically requires two maneuvers, the first to change to a path that intercepts the destination orbit and then a second maneuver to adjust the trajectory to match the destination orbit.

Currently three orbit maneuvers are supported (more will be available in the next release):

  • Hohmann: transfer from one circular orbit to another in the same plane
  • Bi-Elliptic: Transfer from an inner circular orbit to a outer circular orbit via a three maneuver path that saves energy (but takes longer) than a Hohmann transfer. This orbit is only energy saving if the destination orbit has a radius more than 15 times the initial orbit radius.
  • Circularize: A single maneuver to change the current orbit to a circular orbit.


Note that these are orbit transfers. These are distinct from orbit rendezvous. Rendezvous has the additional constraint that the transfer must start and finish at specific times to ensure the arrival at the destination orbit matches an object moving in that orbit. This alignment in time is called “phasing” the orbit. Rendezvous is planned as a future feature in GE.

The code in the UserInterfaceRV script (in Demos/MiniGames) provides a starting point for a script example for how to determine an orbit transfer. The required code can be found in the CalculateTransfers() method:

private void CalculateTransfers() {

    // Find xfer choices and present to user
    transferCalc = new TransferCalc(playerShip.GetNBody(),
    transfers = transferCalc.FindTransfers();
    int count = 0;
    foreach (OrbitTransfer t in transfers) {
        // need a new variable for each lambda
        int _count = count++;
        orbitSelectionPanel.AddButton(t.ToString(), ()=>OrbitSelected(_count) );

Rocket Engines

Rocket engines provide continuous thrust of a massless NBody in the scene. To make use of a Rocket Engine a script extending the RocketEngine class is attached to the NBody. Two implementations are provided in GE 1.6:

  1. OneStageEngine
  2. MultiStageEngine

These engines provide an inspector panel to define the mass of the spaceship, fuel and thrust.

GE provides trajectory prediction for  powered flight (if GE trajectory prediction is enabled).

The inspector panel for the MultiStageRocket is:


The units for mass, thrust and time are kg/N/sec. respectively. These are adapted to the chosen Gravity Engine unit system internally. The values in this example roughly correspond to those of a SpaceX Falcon9 rocket.

The implementation of a rocket engine class hinges on an implementation of the acceleration function (link to doxygen). This function is used on every integration time step to ensure a smooth, continuous path. This is the best method to ensure accurate simulation of the flight. Note that to optimize the integration code this function is only called from the MasslessBodyEngine; the efficiency of the evolution of masses in the scene will not be affected by rocket engines.

The MultiStageEngine is used in the Demos/MiniGames/LaunchOrbit scene. A code example for triggering a stage separation can be found in the DropStage() function in LaunchUI.cs (Scripts/Samples/Launch/LaunchUI.cs).


GravityEngine relies on the Unity collider components to detect collisions via trigger events. It does not make use of them to handle the physics of the collisions.


NBodyCollision is attached to the CHILD of an NBody object. It is typically attached to a MeshFilter object with a Collider and Rigid Body attached. The Collider/Rigid body configuration must be:

  1. Collider IsTrigger Enabled
  2. Rigid Body IsKinematic Enabled
  3. Rigid Body Mass set to 0 (will appear as a very small number in inspector)
  4. RigidBody UseGravity Disabled

The NBodyCollision object will handle the trigger events from the collider and interact with the GravityEngine to achieve the desired outcome.


Collision Type

Defines how the collision should be handled. One of:

ABSORB_IMMEDIATE: On trigger detection the object and its NBody parent will be removed from the scene. The parent NBody’s momentum will be added to the body that it made contact with.

ABSORB_ENVELOP: Once the body with this component has completely entered the other body (based on sphere sizes) the object and NBody parent will be removed from the scene. The parent NBody’s momentum will be added to the body that it made contact with. Envelop works reliably only when the sizes of the objects are different.

EXPLODE: On contact the object and NBody parent will be removed and a particle explosion will be triggered. When selected this element requires an additional parameter: Explosion Prefab

BOUNCE: On contact the parent NBody will reverse direction (as will the parent NBody of the object it made contact with). When selected a Bounce Parameter is displayed. This is value in the range 0..1 with 1 indicating a no energy loss full bounce.

EXPLODE_OR_BOUNCE: Based on contact velocity either explode or bounce.

Collision Precedence

In cases where two bodies with NBodyCollision scripts collide, one must take precedence. The body with the lower precedence will be run. If the precedences of the objects are equal, the Unity game object unique id is used to break the tie.

System Builders

Solar System


Scenes with planets, comets and asteroids can be created using the SolarSystem component. A prefab of this object is provided in the Prefabs/SolarSystem folder.

The Solar System component is interactive and provides an “Add Body” button to start a dialog to allow the developer to select the object type (Planet/Asteroid/Comet) and the specific object. If the object is not in the database provided there is an option to open the Jet Propulsion Lab/NASA database in a browser so the desired object can be found. The orbital parameters for the object can then be pasted into the object creation dialog. The JPL/NASA database lists all known comets and asteroids – over 500,000 objects in total!

When using the Solar System builder the unit system in the Gravity Engine must be set to SOLAR. This selects units of AU, 1E24kg and year. The Solar System inspector allows the start date to be specified and the objects will be moved to the position corresponding to that date.

The scale of the planets is centrally controlled from the Solar System builder to allow the planet scale to be changed maintaining the relative sizes of the planets. The choice of scale in the solar system is challenging if the goal is to show the entire solar system. Mercury orbits every 88 days and Neptune orbits in 165 years. The physical scale is similarly challenging. Often it may be necessary to have different scenes for inner and outer planets.



Sets the number of Unity length units per 10,000 km of planet radius. For reference, Earth has a radius of 6378 km, Jupiter 71,492 km.


Specify the start date for the solar system. This will modify the positions of the bodies in the scene.


When bodies are added they are constructed from the prefab of the corresponding type. The prefab objects must contain NBody, OrbitEllipse and SolarBody components (SolarBody is used to hold the reference values of the orbit prior to scaling).

The Prefab may optionally contain a child with a Text component. If present the SolarSystem will insert the object name when the object is created. If the solar system is then made a child of a World UI Canvas then these text labels will be visible.


Open a dialog to add a body to the scene. The Add Body dialog will appear:


The type of body is selected by the first selection box. Each of PLANET/ASTEROID/COMET provides a selection box of well know celestial objects. If the desired object is not on these lists then the JPL_ASTEROID/JPL_COMET modes allow the parameters for a body to be located in the NASA/JPL database and then pasted into the dialog.


The RandomPlanets script is used to create a system of planets in random orbits around a central body when the scene starts. It allows control of the number of planets and a range for each of the orbital parameters. In order to allow more than one planet game object type it allows a list of planet prefabs to be provided and will pick randomly from the list for each planet creation.

This script is also a useful example demonstrating how to procedurally create and link planets.

Screen Shot 2016-08-24 at 6.29.12 AM.png

Number of Planets: The number of planets to be generated

Planet Prefabs: A list of prefab objects that will be used to create the planets. The prefab planet structure must match the examples in the prefab folder:

  1. Base game object with an NBody and OrbitEllipse component
  2. A child game object with a MeshRenderer to display to model for the planet.

Orbit Parameter Ranges: Min/Max ranges to be used for each of the orbital parameters of the planets.

Renderer Scale: Min/Max range of the local scale to be applied to the models of the planets as they are created.

Scripting Interface

Scene setup can also be done under script control. Documentation for the script interaction in HTML and can be found in html/index.html.


The gravitational interaction between three equal-mass bodies is a long-standing area of investigation in celestial mechanics. Over the past three hundred years a variety of solutions have been found. The Gravity Engine asset provides a set of these solutions, coupled with a special algorithm to allow them to evolve through regions where the bodies come very close to each other.

These solutions can be explored using the ThreeBodySolution script. They can also be found in the app ThreeBody available on iOS and Android. (The Gravity Engine asset derives from the work done on ThreeBody).

This component is added to a top-level game object in the scene. (Typically it is added to the GravityEngine game object).


Solution Set

Name of the solution set to select a specific solution from.


Name of the solution from within the solution


Nbody objects with mass 1 to be used in the scene. Their positions and initial velocities will be initialized based on the solution that has been selected when the scene starts.

Modifying the Gravitational Force

Screen Shot 2017-02-20 at 11.26.41 AM

Orbit due to 1/R force

The GravityEngine class allows for the force between masses to be changed – allowing the game developer to explore universes with non-standard physics. This can be done by selecting a different FORCE under the Advanced tab in the GravityEngine inspector. There are a number of built-in alternatives (the function of distance is indicated in parenthesis):

  1. InverseR (1/R)
  2. InverseR3 (1/R^3)
  3. ForceR (R)
  4. ForceR2 (R^2)
  5. Custom (requires a class attaching the force delegate interface be attached to the GE object).

The usual closed orbits that arise due to gravity are special. An object in a gravitational orbit returns to where it started from after one orbit. For other forces this is not true (with the exception of R^2) and the orbit will instead form a “spirograph” type pattern, the details of which depend on the force law. In reality in close proximity to a large mass the same effect happens in the real world – an effect due general relativistic effects. Famously, the orbit of Mercury when measured over decades is not exactly closed.

If the force is changed to something non-standard then the built-in orbit tools (OrbitEllipse, OrbitHyper, BinaryPair) will not show the correct paths. They determine paths with a the standard equations of gravity.

Defining a New Force

To define a new force requires a class inheriting MonoBehaviour and implementing the IForceDelegate interface. This interface requires that the force law and (optionally) it’s derivative be provided as methods:

  • calcF(double R) force function in terms of R only
  • calcFdot(double R) derivative of force with respect to R. This is optional. It is used if the Hermite integrator is selected. [To calculate derivatives symbolically you can use one of many online tools found on the web]

This class must then be attached to the same game objects as the GravityEngine script and the Force must be chosen as Custom.


Gravity simulation deals with mass, distance and time. The units/scale for these elements in simulation is never in the standard units of physics (sec, m, kg). In general simulations rescale time, mass and distance to allow the computations to use numbers of “reasonable size”. The range of the number depends on the range of values being modeled. For example, in a Solar system simulation it may be useful to work in terms of “Jupiter masses” and set the mass of Jupiter to 1 and the mass of the Sun to 1047.56. (Wikepedia: Jupiter Mass).

The effect of scaling can be understood via Kepler’s third law:

G (m_1 + m_2) T^2 = L^3

The effect a change of the scale of mass and distance is summarized in Table 1:

Change Effect Change by 2x Change by 0.5x
Mass Orbital speed increases as mass value increases Evolve 1.4 x faster Evolve by 0.7x slower
Distance Orbit speed slows as distance increases Evolve 0.35 x slower Evolve 2.8 x faster

Gravity engine sets G=1 (to avoid multiplying by G in every force calculation).