First, you should not have a strict 1-1 mapping of Components to Systems. It's unclear to me from your question if that's the case already. You may very well have singular systems that use or interact with numerous components. Rendering, physics, AI, etc. are all Systems (they perform a cohesive set of updates and logic) but interact with many Components.
A System needs to be able to store a list of entities that match some particular Signature. e.g., if physics requires BodyComponent
and TransformComponent
, then the PhysicsSystem
needs a list of all entities that have both of those two components.
Solution 1
A System also likely needs multiple such lists, as you're finding. RenderSystem
needs to know about all Renderable+Transform pairs, as well as all Camera+Transform pairs, and that's only for a very simple rendering engine (once you get particles, post-processing, terrain, foliage, skinned meshes, etc. it gets more complex).
Solution 2
The other alternative that I'm rather fond of is to stop trying to use the ECS pattern. If you split all your engines (physics, graphics, AI, audio, etc.) up into separate libraries (which is probably already the case for physics since most people use off-the-shelf libraries there) then you'll note that you need each to exist independently of your ECS framework.
For instance, when you load an entity up and see that it has a PhysicsComponent
you call into your physics library's CreateBody()
function with all the data from the entity; that will usually return some kind of pointer or id. Store that into the PhysicsComponent
. Most of the rest of the data you loaded off disk can possibly even just be thrown away since it'll all be copied into the physics library's internal data structures. Really all you're left with is some glue so when game logic needs to add a force to a game object it can find the appropriate pointer to the physics library's body object.
Your Components end up mostly just being glue that holds your convenient data-driven game objects together with the external handles/objects managed by your engine libraries. You're more likely to find that you don't need Systems at all anymore and possibly (for simpler games) don't even need Components, either.
Depending on your choice of libraries or how you decide to implement Components, this may still even end up looking a lot like an ECS. For instance, instead of storing a PhysicsComponent
that holds a pointer to a rigid body object, your library may allow you to attach a unique ID to a body when it's created and then query for bodies by ID; that would allow you to attach the EntityId
to the corresponding physics body and then write a ComponentMapper
facade that queries your third-party physics library instead of a custom component data structure. I question the utility of such a design myself, but it's certainly something you could do.