How can I solve the same problems a CB-architecture is trying to solve without using hacks? [on hold]
- by Jefffrey
A component based system's goal is to solve the problems that derives from inheritance: for example the fact that some parts of the code (that are called components) are reused by very different classes that, hypothetically, would lie in a very different branch of the inheritance tree.
That's a very nice concept, but I've found out that CBS is often hard to accomplish without using ugly hacks. Implementations of this system are often far from clean. But I don't want to discuss this any further.
My question is: how can I solve the same problems a CBS try to solve with a very clean interface? (possibly with examples, there are a lot of abstract talks about the "perfect" design already).
Here's an example I was going for before realizing I was just reinventing inheritance again:
class Human {
public:
Position position;
Movement movement;
Sprite sprite;
// other human specific components
};
class Zombie {
Position position;
Movement movement;
Sprite sprite;
// other zombie specific components
};
After writing that I realized I needed an interface, otherwise I would have needed N containers for N different types of objects (or to use boost::variant to gather them all together). So I've thought of polymorphism (move what systems do in a CBS design into class specific functions):
class Entity {
public:
virtual void on_event(Event) {} // not pure virtual on purpose
virtual void on_update(World) {}
virtual void on_draw(Window) {}
};
class Human {
private:
Position position;
Movement movement;
Sprite sprite;
public:
virtual void on_event(Event) { ... }
virtual void on_update(World) { ... }
virtual void on_draw(Window) { ... }
};
class Zombie {
private:
Position position;
Movement movement;
Sprite sprite;
public:
virtual void on_event(Event) { ... }
virtual void on_update(World) { ... }
virtual void on_draw(Window) { ... }
};
Which was nice, except for the fact that now the outside world would not even be able to know where a Human is positioned (it does not have access to its position member). That would be useful to track the player position for collision detection or if on_update the Zombie would want to track down its nearest human to move towards him.
So I added const Position& get_position() const; to both the Zombie and Human classes. And then I realized that both functionality were shared, so it should have gone to the common base class: Entity. Do you notice anything? Yes, with that methodology I would have a god Entity class full of common functionality (which is the thing I was trying to avoid in the first place).