[quote name='Hodgman' timestamp='1324860026' post='4897366']Just for some food for thought: it's entirely possible to implement a component/entity system without even providing a "get child component by type" function whatsoever -- getting a component by type is just one way that you can choose use a component/entity system, with it's own robustness/predictability/maintenance pros/cons.
Would you mind clarifying on that point? Would you instead get a component by instance id? Is what you're suggesting use tables in someway?[/quote]It depends on what your use-cases are for the "[font=courier new,courier,monospace]GetComponent<T>()[/font]" function, but I'll use an example to illustrate what I assume to be some common use cases:
* We're writing a "rocket launcher" component.
* When firing, it searches it calls [font=courier new,courier,monospace]parent->GetComponent<Transform>()[/font] in order to know where to spawn the rocket from.
* Rockets have a chance of mis-firing, which does damage to the holder - when this happens, it calls [font=courier new,courier,monospace]parent->GetComponent<Health>()[/font] to know where to apply the damage.
The user of the system is now happy that when they add a rocket launcher to an entity, it magically knows from where it should fire, and where it should apply "mis-fire" damage.
In my opinion, the above magic is exactly what makes this design a completely awful piece of architecture -- it makes the software engineering part of my brain feel dirty for hiding known dependencies away under an abstraction in order to achieve
spooky action at a distance, which is never a good thing when it comes to being able to reason about the state and interactions in your program.
It also has the problem of enforcing the
there can only be one philosophy onto the user -- each entity can only have one transform and one health component -- which may seem like a trivial burden at the time of writing, but at some point your users will find a reason for there to be two of something, and will be forced to construct ungracious work-arounds involving several entities cooperating to function as one "entity".
All of these engineering taboos can be easily avoided if the rocket launcher is simply told in advance which health/transform components it is going to be interacting with, instead of acquiring them by magic (type). This could simply be done by giving the rocket launcher component some properties that the user can set, which contain the names of the linked components.
Another example of how you can connect them is during construction, e.g. in the "
entity is a vector<component*>" abstraction, you could write something like this:
Transform* transform = new Transform();
Health* health = new Health();
entity->Add( transform );
entity->Add( health );
entity->Add( new RocketLauncher(transform, health) );
N.B. these ideas also translate over to the "
entity is an int, and systems are a map<int,T>" abstraction.