I'm excited by this feature, along with all the other compile-time programming stuff (reflection, concepts). The downside I see is having to remember how a metatype works.. e.g., the default access type for member variables of struct, class, interface, value, .. and on and on. But if we keep the number of metatypes low, this may manageable.
Have you written about this in more detail Jon? I'd love to read about it.
I'm not sure if there's an explicit definition somewhere, but i think an ECS could be as simple as an entity struct that contains an (optional) physics struct, that is then operated on by some physics module.
Although Quake2 certainly is industry-proven, it doesn't feel right for every specialized entity behaviour function to depend on members needed by other specialized entity behaviour functions.
The way I do it, each entity has one struct. So a Bullet is one strict and a Door is one struct. They both share common base members that all entities share.
But this is all that is really necessary. Once you start getting into components, you add a lot of complexity (even if the pitch is that it's "simple").
I'm not fully convinced by components either, I don't like the idea of the bullet behaviour code having to check if "this entity has 'propeller' and 'rigid_body' components", as if the bullet behaviour code had to re-discover what a bullet was made of (BTW, this feels like a re-implementation of coarse-grained dynamic duck-typing for static languages).
This problem is less visible when the game logic is written in Lua, where dynamic duck-typing is the rule.
I do write my game logic in C++/D, though, and the problem is perfectly visible.
The way you describe how you would do it raises a few questions ; because now it seems you can't process entities in a systematic/opaque way.
This implies that, say, the renderer has to loop over bullets, then to loop over doors, and so on. Each time a new entity type is added, this part of the code has to be modified, even though most entities might share the drawing code (e.g mesh).
This sequence of loops appears in many places, like collision checking, game logic update, save/load, etc. and all of them have to be updated when a new entity type is added.
Something in my understanding must be wrong, because the way you do it obviously works ; maybe the issues I just described isn't so problematic in practise?
I do think it is a useful exercise though to go through your entities and see if these various "components" or attributes of one entity make sense with another entity. Like, if you have a RTS with some resources and units, which of the units' attributes could apply to a resource? What if a resource could attack? Or if it could move (e.g. deer in AoE)? Or maybe it can be destroyed and explodes doing damage with a large blast radius. I think as a practice this approach generates a lot of creative ideas and leaves an opening for making these changes late into the process of programming a game.
It's a problem, but I'm not sure it's a big enough problem to seek out an alternative architecture altogether.
Bullets probably would be simple structs in a shooty game, not full blown entities.
The next step beyond that simple approach is to store the components outside the entity. E.g. using SoA that Jon's new language has support for.
In my game (http://moonman.io) i use an approach similar to that in the bitsquid engine, with static polymorphism and crtp and other nonsense. It works but i admit is probably overkill.
> Bullets probably would be simple structs in a shooty game, not full blown entities.
Why not?
You still need to render bullets, to load/save them to disk, to synchronize them over a network ; some of them move by themselves, they physically interact with the rest of the world, play sounds, and have animations. And actually, many other entities also inflict damage on collision (spikes, forcefields ...).
So from the point of view of your game low-level internals, there's nothing very specific about bullets.
BTW, the same applies with powerups, doors, monsters, spikes, moving platforms, ...
But some bullets might have a locked target, some powerups might disappear after a while, some doors might need a key to be open ... these behaviours are typically not shared between game object types ; I might be wrong, but having a new component/array for each of them also seems overkill.
> The next step beyond that simple approach is to store the components outside the entity. E.g. using SoA that Jon's new language has support for.
For one second I thought you were talking about "service-oriented architecture" :-)
You could definitely make them full entities, it would depend on your use case. If you're making a bullet hell shooter then maybe bullets need to be handled as a special case. Either way best not to get caught up in ideology or finding a perfect architecture, just do what works for you and your game.