2
\$\begingroup\$

I have a working ECS-system set up, largely inspired by this brilliant article (not at all required reading to be able to answer my question) on https://indiegamedev.net/ showcasing an ECS-system with proper data locality. I've modified it quite a bit, but the general layout of the API is pretty much the same.

struct SystemFunctor
{
    void operator()
        (float timeSteps, const std::vector<EntityID>&,/*(arrays ->)*/PhysicsComp*, RenderComp*);
};
void system(float timeSteps, const std::vector<EntityID>&,/*(arrays ->)*/PhysicsComp*, RenderComp*);
...

SystemFunctor f;
engine.registerSystem<Engine::RENDER_LAYER_1>(f);

engine.registerSystem<Engine::RENDER_LAYER_1>(system);
/* Both of these calls register a system that operates on entities with at least a 
PhysicsComp and a RenderComp, and will be called when the system layer RENDER_LAYER_1 is run. */

As the title reads, my question is: How can entities that have no component types in common interact with each other? Since a system only receives data from entities whose types are a subset of the entity composition it operates on, how could it receive the data it needs to perform interactions between wildly different entities?

To get a little more specific, here is the current problem I'm trying to solve:

I'm making a small exercise program where the user draw points on the screen with the mouse, and a point-quadtree for all the points is recomputed and drawn (as boxes) on the screen when new points are added.

The adding and rendering of the points was easy - just one system that checks for input and creates the points and another one for rendering them. But when it comes to storing and managing a quad-tree that can come into contact with the point entities I'm at a loss.

Naturally, you would have some kind of quad-tree component:

struct QuadTreeComp
{
// Whatever data your quad-tree implementation uses
};

But from there, I can't seem to figure it out. How do you set up a system that operates on one entity (the one with the QuadTreeComp) while also operating on a bunch of other entities, i.e. the points?

One possible solution I could see is that the system functor that updates the quad-tree doesn't actually operate on QuadTreeComp, but on the points. In its constructor it instantiates an entity with the QuadTreeComp and stores the entity id. Then in its actual function body, it can get the quad-tree component using the id and update it with the points.

class UpdateQuadTree
{
public:
    UpdateQuadTree(Engine& engine):
        engine_{engine},
        quadTreeEntity_{ engine.newEntity() }
    {
        engine.add<QuadTree>(quadTreeEntity_);
    }
    void operator()
        (float timeSteps, const std::vector<EntityID>& entities, Vector2f* points)
    {
        QuadTree* quadTree = engine.getComponent<QuadTree>(quadTreeEntity_);
        /*
                                      ^
                                      |
                            Already an existing function in my ECS-API
        */
        
        // Update the quad-tree using the points...
    }
private:
    EntityID quadTreeEntity_;
    Engine& engine_;
};

The problem with this one is that don't see how other systems that operate on the quad-tree, like the one that renders it, would know the id of the entity.

What would be the textbook-ECS-way of performing these interactions?

\$\endgroup\$

You must log in to answer this question.

Browse other questions tagged .