I am trying to design a data-oriented ECS engine. The issue I am struggling with is that my rendering system have to rely on two different sets of entities to actually do rendering.
My current idea is to have (usually one, but possibly more) entities representing cameras (e.g. sets of components describing views and viewports). Then, I can have RenderingSystem
that iterates through all CameraComponents
and renders everything they 'see' to appropriate viewports.
However, this requires RenderingSystem
to query for two non-intersecting sets of components: cameras
and renderables
. My current approach allows systems to select a set of nodes that have one or several required components. It does not allow for more complex queries, like either CameraComponent
or RenderableComponent
. This is not the first time when more complex system-component dependencies (using unions of component sets insetead of their intersections) seem useful to me.
Plain old data components have crucial advantages:
- They are trivially serializable
- Can be changed by game designers without recompilation or coding knowledge
- Describe behaviors in purely declarative way
That is why I would like to put cameras among other things in the ECS.
Use case: if we are implementing mirrors, we may put Renderable
, Position
and Camera
components on them, then Renderable's
texture will also be a render target for Camera
. RenderingSystem
then will render them in some efficient way.
So, is defining more complex relations with components (like "this system should receive all nodes that have Camera
and Position
as 'cameras' collection and all nodes with Renderable
and Position
as 'renderables') the most flexible solution in this case, or is there a better way?
UPDATE(1): I ended up allowing systems to define their dependencies like this (the word "aspect" is borrowed from Artemis ECS framework):
aspects: {
renderables: Aspect.all(['Transform', 'Sprite']),
cameras: Aspect.all(['Transform', 'Camera']),
emitters: Aspect.all(['Transform', 'ParticleEmitter']),
...
}
These lists are gathered, passed to a system, cached and rendered in an efficient way. This actually works quite nicely (in other systems too), as well as cameras being entities. Is this a common way to do it?
UPDATE(2): I have spent some time working with ECS-like architectures and added a conclusion as an answer. I hope it makes clear that the approach I have suggested in the first update is just one of available options.