Skip to content

Demo: N-Body Problem

This demo demonstrates N:N relationships in an ECS, and how to set up and simulate an arbitrary number of bodies in a generic way.

Source Code

This demo is available for the following:

MonoGameGodotFlaxUnigineStrideRaylibNeoAxis
MonoGameGodotFlax EngineUNIGINE UNIGINEStrideRaylib-csNeoAxis Engine NeoAxis Engine

Video (Godot Version)

Remarks

Case in point here is not raw performance (although the basic GDscript-driven line trail rendering easily eats 90% of the Godot rendering time). Instead, note how short and concise the simulation loop stays - without as much as a single reverse lookup.

cs
// Clear all forces
_accumulator.Blit(new Acceleration());

// Accumulate all forces (we have only 1 attractor stream, this will enumerate each sun 3 times)
_accumulator.For((ref Acceleration acc, ref Body self, ref Body attractor) =>
{
	if (self == attractor) return; // (we are not attracted to ourselves)

	var distanceSquared = Mathf.Max(0.001f, MathF.Pow(Vector2.DistanceSquared(attractor.position, self.position), 0.75f) / 100000f);
	var direction = Vector2.Normalize(attractor.position - self.position);
	acc.Value += direction * attractor.mass / distanceSquared / self.mass;

	// Just a pinch of dark matter to keep things together a bit more
	acc.Value -= self.position * 0.005f / self.mass;
});

// Integrate accelerations, velocities, and positions
_integrator.For(
uniform: (float)delta,
action: static (float dt, ref Acceleration accel, ref Velocity velocity, ref Position position) =>
{
	velocity.Value += dt * accel.Value;
	position.Value += dt * velocity.Value;
});

State and Structure are stored in the Components on the Entities:

  • 1x Body as Plain Component (contains mass and last position)
  • Nx Body as Entity-Entity Relation (once for each other body)
  • 1x Position, Velocity, Acceleration (for physics sim)

The state is transferred into the Game Engine directly talking to the Nodes.