Recently I've been throwing problems at Entity Component Systems to see how far I can push the paradigm. One problem in particular I struggle with, which is writing an elegant implementation of the n-body algorithm.
First, let me clarify the terminology of ECS:
- Component: a structure that holds data
- Entity: a unique identifier used to associate and retrieve component data
- System: logic executed on entities that have a specific set of components
In ECS, for every frame, each system linearly walks over the matching entities. A typical ECS implementation lays out data consecutively in memory per component, which has as advantage that it is very CPU-cache friendly.
To implement n-body, we could have three components (Location, Mass, Speed). We could then have a system called Gravity, which will update the speed of all entities that have Location, Mass and Speed. Then there could be a Move system that walks over entities with Location and Speed, and updates the locations.
For every matching entity, Gravity will have to walk over all the entities (minus one) to compute the attraction force. The first problem is, how do I efficiently get the relevant entities? A query seems wasteful since the entity set it needs is the set that Gravity is already walking over.
The second problem is when entity A computed the attraction force from entity B I'd like to reuse the computed distance when calculating the attraction force from A on B. Ideally these two computations take place in the same iteration. That, however, impacts how I iterate over the entities. If I computed A <-> B when I processed A, I don't need to iterate over A anymore when processing B.
I am not actually interested in the most practical way to implement n-body, but am curious if/how this kind of problem can be elegantly implemented with ECS.