2
\$\begingroup\$

What would be the downside to using a generic all-encompassing Component class versus specific classes (PositionComponent, InputComponent, et cetera) for each component in an entity/component system?

By 'generic' I mean:

class Component {
  String name; // component name, like "position"
  Map<Key, Object> attribs; // Attributes like "x" and "y" stored here.  
}

Where a 'specific' component might be:

class PositionComponent {
  int x, y;
}

I feel like creating a separate class for each component means tons of 3-5 line classes in my code-base.

\$\endgroup\$
6
\$\begingroup\$

There are a few things to watch out for in the "generic" component approach you propose:

  • It means that a component is pure data, and cannot have any behavior unless you start doing things like allowing behavior objects (function pointers, or what-have-you) to be stored in the attribs member or in a similar member. This is a valid possible approach for an ECS, but not all ECS's choose the "component is pure data" model, and it's certainly not the only approach.
  • The generic component stores all attributes in a dictionary; this means string (or some kind of key) lookups to recover data, boxing, and non-contiguous storage. The associative container also has storage overhead. All of these have performance impacts. You are also abandoning type-safety.
  • Storage of the name as a string (rather than being able to intuit it from the type of the component) also means extra overhead.

Personally, I've never seen a "generic component" like you proposed out in the wild for anything real. It seems like a terribly poor choice, if for no other reason than when you have generalized the component so much you might as well reduce the overhead by making the entity the thing that stores all those properties, and namespace them:

class Entity {
  Dictionary<string, object> components;
}

// ...

var entity = new Entity();
entity.components.Add("Position.X", 1.0f);
entity.components.Add("Position.Y", 2.0f);
entity.components.Add("Position.Z", 3.0f);
entity.components.Add("RigidBody.Mass", 100.0f);
entity.components.Add("Killable.HP", 15.0f);

(But I still don't recommend it.)

\$\endgroup\$
  • 5
    \$\begingroup\$ Also, consider the typos like "Killalbe.HP" the compiler won't catch - good luck finding those. To fix this every dictionary key should be created as static/const string and that brings us back to simply defining the variables in the interface in the first place. \$\endgroup\$ – LearnCocos2D Dec 17 '13 at 8:58
  • \$\begingroup\$ I may misunderstand the ECS concept a bit, but isn't a component supposed to be pure data, with the systems operating on the components to define behaviors? Sorry, I guess I don't understand the benefit of an ECS if you're mixing your behavior with your data. Any sources on the web about that? :) \$\endgroup\$ – ALW Dec 17 '13 at 23:50
  • \$\begingroup\$ There is no single, universally-accepted definition of an ECS, and there are plenty of existing ECS implementations that allow components to have behavior. "ECS" is just a rough pattern to follow, flavors where components have and don't have behavior are both equally valid. \$\endgroup\$ – user1430 Dec 18 '13 at 3:01
  • \$\begingroup\$ Thanks Josh. I did a pro/con list based on your answer and ultimately I came away with the class-based approach you advocated. Two major pros stuck out for me: computed properties, and self-documenting components. I'm accepting this answer. \$\endgroup\$ – ALW Dec 19 '13 at 2:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.