frob said:
std::vector<IThing*> things;
...
for(IThing* thing : things )
{
thing->DoStuff();
}
First of all, I've not implemented an ECS, this is just from what I've read.
From what I am understanding about ECS, usually you would implement it exactly not this way, if you try to archive best performance.
An entity is just a collection of components (in the most extreme case, an entity is just an array index), the component hold the data. Neither the entity nor the components implement functionality, thus they don't have methods like DoStuff(). The systems implement the logic, thus the system will have a method like DoStuffForManyThings() which will then iterate over the entities that are relevant for the system.
The system will, for each entity that has the correct components, gather the relevant data needed to perform the current task from the components it requires and ignore any additional components the entity has.
It's hard to illustrate this with just Thing, so maybe let's assume there are multiple components available.
For example a couple of physics components like:
a PositionComponent, an OrientationComponent, a SizeComponent, a VelocityComponent, a WeightComponent, a BoundingVolumeComponent, a CollisionMeshComponent
and a few rendering components like:
a MeshComponent, a SkeletalAnimationComponent, a TweeningAnimationComponent, a TextureComponent, a ShaderComponent, a SpecialEffectsComponent
And so on....
In reality you would probably be more flexible if you allow multiple Meshes, Textures, Effects e.g. by using a MeshListComponent or something, this is just a simplification, but it's just an example.
You could also argue the BoundingVolumeComponent should be placed in the rendering component category, but in reality the distinction between rendering and physics components is not made or at least not so coarse.
Now entities can have some of those components, but of course don't have to have all of them.
Let's say entity A is a statically placed component that can't move, but in the game world it is visible, is not animated and other objects can collide with it.
Entity A has a PositionComponent, an OrientationComponent, a SizeComponent, a BoundingVolumeComponent, a CollisionMeshComponent, a MeshComponent, a TextureComponent, a ShaderComponent, a SpecialEffectsComponent
Let's say entity B is something like an Indicator on a Map or a Label, it can move, it is visible, it can be animated, it doesn't physically interact with other objects in the game world.
Entity B has a PositionComponent, an OrientationComponent, a SizeComponent, a VelocityComponent, a BoundingVolumeComponent, a MeshComponent, a TweeningAnimationComponent, a TextureComponent, a ShaderComponent, a SpecialEffectsComponent
Let's say entity C is a unit or actor of some kind, maybe player controlled, maybe ai controlled. It can move in the game world, it is visible and animatable, it can interact with the game world.
Entity C has a PositionComponent, an OrientationComponent, a SizeComponent, a VelocityComponent, a WeightComponent, a BoundingVolumeComponent, a CollisionMeshComponent, a MeshComponent, a SkeletalAnimationComponent, a TextureComponent, a ShaderComponent, a SpecialEffectsComponent
Let's say entity D is a region of the map, maybe some kind of control region. It's not visible, it doesn't really interact with the game units, but it might be used to detect if a unit is in a certain area.
Entity D has a PositionComponent, an OrientationComponent, a SizeComponent, a BoundingVolumeComponent
Now a rendering system would only iterate over the entities that have components relevant to it. We might even split the set of entities into multiple sets that are iterated seperatly.
E.g. we might first want to iterate over all visible but static entities (for example the map itself), e.g. all entities with a MeshComponent, a TextureComponent, a ShaderComponent, a PositionComponent, an OrientationComponent, a SizeComponent and a a BoundingVolumeComponent, but none with one of the animation, special effects or veloocity components. So entity A would be in the set of iterated components. The system, let's call it MapRendererSystem will use the data from within the components (that are relevant to the current task), but it won't call any methods of the entity or components, since there aren't any.
Next we might decide the units should be rendered so the rendering system for example a UnitRendererSystem would iterate over all entities that are visible, moveable and can physically interact with the game world. The systen uses the data from the appropriate components to render the units, other components are ignored.
For me the important aspect of ECS is that the entities are a collection of components, the components store the data, neither entities nor components implement logic, systems are the one place where logic is implemented.
Regarding actual implementation, there are many ways to do this.
If I would implement it myself, I would absolutly not use a shallow but wide inheritance tree and put it in a generic container, e.g. a parent class Component from which all components deriver. That's as terrible as the Java Object from which everything derivers.
In the end the system required specific components and the components are widely different from each other, a PositionComponent is different from a TextureComponent in every aspect. Any parent class Component is going to be a completly empty shell. And since the components don't implement logic they don't have any kind of interface.
Regarding interaction with a non-ECS part of the game or engine. The systems are the ones responsible, it would gather all data from the entities/components it iterated over and send them to the non-ECS-parts of your game/engine.