Trouble switching from inheritance to composition.

Recommended Posts

Hi all,

I just decided to cut down my 1000 year-old inheritance tree because of too many nasty problems you probably already know of.

But I'm trying to draw all the stuff in my head before starting to make such a big architectural change. Big for me, probably not so big for you.

Ok, let's imagine I've rewritten all my classes using composition.

The way I see it, my GameObject will look like this:

class GameObject
{
Matrix transform;
Model* model;
Physics* physics;
Renderer* renderer; //Or I'll just use a static void render(GameObject&) function instead of a whole class, for starters.
}


Ok, cool. But now I need a Player object.

class Player
{
Input* input;
Animator animator; //for skeletal animation
Matrix transform;
Model* model;
Physics* physics;
Renderer* renderer; //Or I'll just use a static void render(GameObject&) function instead of a whole class, for starters.
}


Imagine 10 more different classes like this.

Final step is to render all entities using a 'for' loop.

If I was using my bad old inheritance tree, I would just do:

for( auto& object : gameObjects ) { Renderer::draw( object, viewCamera, interpolationRatio ); }



And have no problems since every monster inherits from GameObject.

But now that I have 10 classes for 10 different monsters, how do I render them at once? :huh:

2. Stuffing every component in the world in the GameObject and using flags doesn't count. It will become too fat, I'm sure.

3. Entity-component-system is too much. I just want to make a simple game like a normal person.

Heeelp! :o

Edited by codeBoggs

Share on other sites

Thanks to all for the replies. ^_^

WoopsASword, inheritance is not the way to go, man. Or maybe I'm just missing something, but I doubt it. I would really like to switch to using components.

I don't say inheritance is bad as a tool, it works, but it doesn't work when it becomes a big, fat tree that I'm afraid to inherit from, because I get loads of functionality that I don't want just so I can get 2 functions I need. And I always wonder whether I should copy/paste some code, or inherit, but I don't want multiple inheritance, and yeah...

Guys, I kind of like the idea of putting 100k components into GameObject and then if I want to use something, I just set the flag to true. The GameObject will be giant, but once I get used to it, I will be ok. Bear in mind that I don't have a team, so readability for others is not an issue. What do you think?

Edited by codeBoggs

Share on other sites
What do you think?

I think you should use the tools that are the best suited for what you want to achieve.

Inheritance represents "is-a" relationships. It's perfectly suited for when you want to model inheritance.

Composition represents "has-a" relationships. It's perfectly suited for when you want to model composition.

Swapping everything to composition or swapping everything to inheritance seems like a really bad idea. Use what's appropriate, when it's appropriate.

If your problem is having a "big fat tree" that you're afraid to inherit from, that's a sign that you probably shouldn't inherit from it in that case.

Either because your base object is far too complex, or because the thing you are trying to model does not fit the inheritance model.

If you can guarantee something is common for absolutely everything, put that as the common object and inherit from that.

EDIT: That is to say... don't swap for the sake of swapping. Swap if and when there is a good reason to swap.

Edited by Lactose

Share on other sites

Lactose!, there are many reasons. I just can't code anymore man, my code is a mess. And I'm not productive.

For example, if I have a Character like this

class Character
{
CollisionBox box;
Health hp;
Input* input;
Animator animator; //for skeletal animation
Matrix transform;
Model* model;
Physics* physics;
Renderer* renderer;
}


Imagine my character has the magic ability to become invisible, where he can go through walls and doesn't take hp.

So when the character is invisible, I would just like to remove the CollisionBox and Health out of the equation. With inheritance it's messy and ugly. But with composition, I can just remove the Health and the CollisionBox components when I'm invisible, and add them back when I'm visible, for example.

EDIT: Entity-component-system is shitty, because I don't want to put all of the behaviour in a system and leave the components to be just data, I mean who does that stuff??  <_<

And inheritance is ugly, not flexible or extendable and not readable, there's no argument about that. :angry: Talking about games here, not business stuff.

Need to come up with something else, but needs to be doable in C++, of course. :wacko:

Edited by codeBoggs

Share on other sites

I decided on switching to composition and putting both data and behaviour in the components. And if some data is shared by more than one component, I will declare it in the entity. But I will use shared variables only for the basic stuff, to keep the entity clean. And for the other stuff, I will just send messages between the objects somehow, will figure that out later. ^_^

EDIT: Now I decided to put all possible components in GameObject, and do like this:

  if (self.hasRender) {
[self updateRender:dt];
}
if (self.hasHealth) {
[self updateHealth:dt];
}
if (self.hasTeam) {
[self updateTeam:dt];
}
if (self.hasGun) {
[self updateGun:dt];
}
if (self.hasMove) {
[self updateMove:dt];
}
if (self.hasDamage) {
[self updateDamage:dt];
}
if (self.hasPlayer) {
[self updatePlayer:dt];
}
if (self.hasAI) {
[self updateAI:dt];
}
if (self.hasHuman) {
[self updateHuman:dt];
}


Simple and cool for noobs like me.

Edited by codeBoggs

Share on other sites

Thanks to all for the replies. ^_^

WoopsASword, inheritance is not the way to go, man. Or maybe I'm just missing something, but I doubt it. I would really like to switch to using components.

I don't say inheritance is bad as a tool, it works, but it doesn't work when it becomes a big, fat tree that I'm afraid to inherit from, because I get loads of functionality that I don't want just so I can get 2 functions I need. And I always wonder whether I should copy/paste some code, or inherit, but I don't want multiple inheritance, and yeah...

Guys, I kind of like the idea of putting 100k components into GameObject and then if I want to use something, I just set the flag to true. The GameObject will be giant, but once I get used to it, I will be ok. Bear in mind that I don't have a team, so readability for others is not an issue. What do you think?

I personally prefer a "big fat tree" as long as it's properly designed.

You can't run away from complexity, some code are so complex you have to sit monthes just to understand it.

What can we as developers do? Simplify as much as we can!

Your understanding of what "composition" should consist of is not well.

Composing objects should not interfer with your inheritance.

"100K components into "gameobject"" - This is not how it works.

If not all derived "gameobject" need these 100k objects, than It's not the place for these objects.

"readability for others is not an issue" - There's a special quote for that:

"When I wrote that only me and god knew what it does. Now?  only god".

EDIT:

I decided on switching to composition and putting both data and behaviour in the components. And if some data is shared by more than one component, I will declare it in the entity. But I will use shared variables only for the basic stuff, to keep the entity clean. And for the other stuff, I will just send messages between the objects somehow, will figure that out later.  ^_^

EDIT: Now I decided to put all possible components in GameObject, and do like this:

  if (self.hasRender) {
[self updateRender:dt];
}
if (self.hasHealth) {
[self updateHealth:dt];
}
if (self.hasTeam) {
[self updateTeam:dt];
}
if (self.hasGun) {
[self updateGun:dt];
}
if (self.hasMove) {
[self updateMove:dt];
}
if (self.hasDamage) {
[self updateDamage:dt];
}
if (self.hasPlayer) {
[self updatePlayer:dt];
}
if (self.hasAI) {
[self updateAI:dt];
}
if (self.hasHuman) {
[self updateHuman:dt];
}


Simple and cool for noobs like me.

This is terrible.

Edited by WoopsASword

Share on other sites
This is terrible.

WoopsASword, I kind of disagree, man. And I will tell you why. My game will consist of maximum 30-40 components. This method may not be suitable for large-scale games, but saves a lot of developing time. And I'm doing a small game. In my opinion, there is no terrible code or pattern, there's just code that is not suited for the purpose.

If you still don't agree with me, you can post and tell me why I'm wrong. I'm open to criticism.  ^_^

I think you should use the tools that are the best suited for what you want to achieve.

See, you said it. :cool:

Edited by codeBoggs

Share on other sites

Guys, I kind of like the idea of putting 100k components into GameObject and then if I want to use something, I just set the flag to true. The GameObject will be giant, but once I get used to it, I will be ok.

Use the right tool for the job... However, don't do this. It will become a maintanance nightmare. Splitting things up into modules (composition, inheritance, it doesn't matter) has many benefits.

Share on other sites

Okay, thanks a lot for the explanation, Sean. Good thing I haven't started doing that ECS stuff yet.

EDIT: Now I got what you said. :o You meant that I can create all types of  Characters, Monsters, Trees, Missiles and all crazy stuff, and just use their mesh and transform matrix to render it on screen. Sounds really cool. I haven't thought about that.

Edited by codeBoggs

Share on other sites

there is no terrible code or pattern, there's just code that is not suited for the purpose

The point we're trying to make is that the solutions you've posted are fairly terrible for the given scenario.

As for your question regarding your character with  the magic spell -- to me, that would be an example showing why CollisionBox and Health should not be a part of the GameObject base class. You'd normally derive the player from the GameObject (or a more specialized class deriving from GameObject, as suggested above), and use composition to add in the remaining parts (in this case, the special stuff for collision and health).

Another potentially solution if Collision were derived from another class would be to have collision flags in the collision info, and be able to basically turn off collision against walls, etc. dynamically. You will at some point probably want this anyway, because everything will not collide with everything else the same way. A prime example here was actually given by SeanMiddleditch, with trigger zones. Certain trigger zones might only be triggered by certain types of entities, which could be implemented with various flags.

Share on other sites
The point we're trying to make is that the solutions you've posted are fairly terrible for the given scenario.

Stop lowering my self esteem, man. <_<  Companies reject me enough.

Another potentially solution if Collision were derived from another class

I don't derive. I'm a teetotaler now.  ^_^

But thanks for the help. I will most certainly return to that post in some later phase of my development, because it seems like nonsense to me now.

Edited by codeBoggs

Share on other sites

This is terrible.

WoopsASword, I kind of disagree, man. And I will tell you why. My game will consist of maximum 30-40 components. This method may not be suitable for large-scale games, but saves a lot of developing time. And I'm doing a small game. In my opinion, there is no terrible code or pattern, there's just code that is not suited for the purpose.

If you still don't agree with me, you can post and tell me why I'm wrong. I'm open to criticism.  ^_^

I think you should use the tools that are the best suited for what you want to achieve.

See, you said it. :cool:

"there's just code that is not suited for the purpose. "

This code is not suitabled for your purpose.

There are more drawbacks than advantages in this code, You asked our opinion. That's my expert opinion.

Do w/e you want with it.

Share on other sites
Another way to think about: rather than your system pulling Renderables out of the list of game objects, a game object should push its Renderable into the systems. Invert your dependencies.

Sean, I did the Renderable component, but I don't know why I can't understand that sentence........

Okay, imagine I have classes Monster, Missile and Castle.  And they all have a Renderable component in them. Now I want to push them into a vector in order to draw them at once.

//Create and fill vector.
std::vector<std::unique_ptr<Renderable>> renderables;
renderables.push_back( make_unique<Monster>( glm::vec3( 3.0f, 0.0f, 3.0f ), myResources.monsterAnims, myResources.objectShaders, myResources.getHeightMap() ) );
renderables.push_back( make_unique<Missile>( glm::vec3( 3.0f, 0.0f, 3.0f ), myResources.missileAnims, myResources.objectShaders ) );

//And so on.... Is this what you mean?


And one more question, if you have the time.

Imagine I want to create a MegaFatMissile that is kind of really like a normal Missile
but it's fat and does a lot of damage, but it recharges slower. And I feel kind of lazy and
I want to inherit the MegaFatMissile from the normal Missile instead of copy pasting a few components. Is it ok to inherit just once?
I wont make deep hierarchies or stuff, I mean just once or twice? :huh:

And if I don't want to inherit at all and want to create a new class that will be really like some previous class of mine,
is it ok to add the same components again and just add 1-2 more additional components that are specific to the new class.
It's not a problem to me, I'm just wondering if it's bad practice to copy/paste components like that? :huh:

Edited by bogosaur5000

Share on other sites

Okay, imagine I have classes Monster, Missile and Castle.  And they all have a Renderable component in them. Now I want to push them into a vector in order to draw them at once. //Create and fill vector. std::vector> renderables; renderables.push_back( make_unique( glm::vec3( 3.0f, 0.0f, 3.0f ), myResources.monsterAnims, myResources.objectShaders, myResources.getHeightMap() ) ); renderables.push_back( make_unique( glm::vec3( 3.0f, 0.0f, 3.0f ), myResources.missileAnims, myResources.objectShaders ) ); //And so on.... Is this what you mean? And one more question, if you have the time.

I'm not sure what the make_unique is trying to accomplish with these examples. Are those your GameObject sub-classes? You don't put GameObjects into the renderables list - you should only put their Renderable components into the renderables list. There is no reason to sub-class Renderable for each possible GameObject type. You'd only subclass Renderable for things that are drawn using entirely different code; e.g., two sprites are identical other than the resource they use, so they use the same Renderable.

So a Monster and a Missile both have a Renderable component. Just add that to your renderables list.

Look at the example I posted earlier. It's the creation of the components there that registers _the components_ in the renderables list. You can structure that code in many ways, but the key part is that the components live in the specific list, not the game objects. The game objects live in their own list of all game objects. Yes, there's many lists - one for all game objects and then another list per component type (for any component that you need to iterate over, at least).

Imagine I want to create a MegaFatMissile that is kind of really like a normal Missile but it's fat and does a lot of damage, but it recharges slower. And I feel kind of lazy and I want to inherit the MegaFatMissile from the normal Missile instead of copy pasting a few components. Is it ok to inherit just once?

It's OK if it solves a real problem that inheritance is meant to solve. I'm not sure that it does in this case.

If your problem is just configuring components, move that code outside of your classes. Something like this:

void addMissleComponents(GameObject& object, Texture missileTexture = data.missileTexture, int missileSpeed = data.missileSpeed, /*etc*/) {
}

// just like a normal missile, but some different data instead of the defaults
}

In other words, remember that your basic unit of composition is _functional composition_. Don't make a class out of something that can just be a function. Don't duplicate function code if you can just use a function parameter to alter the behavior instead.

And if I don't want to inherit at all and want to create a new class that will be really like some previous class of mine, is it ok to add the same components again and just add 1-2 more additional components that are specific to the new class. It's not a problem to me, I'm just wondering if it's bad practice to copy/paste components like that?

It's not bad practice to copy-paste component configuration. There may be better tools available in some engines, but many don't have said tools. In Unity, for example, you'd just drag-n-drop the components you need onto your object prefab; there isn't even any kind of inheritance available at that level. The engine we use at work _does_ have a (multi-)inheritance tree you can use to compose objects, which we make heavy use of, but our engine is not exactly structured the way I would ever recommend for you to structure yours. :)

Share on other sites

Okay, frob, I decided to spend 2 weeks on unity. Thanks for the suggestion, again.  :)

There is no reason to sub-class Renderable for each possible GameObject type

Sean, I'm SUPER stupid, I made a mistake when posting my code, really sorry. :(  I don't put the objects(Monster, Missile) in the vector, of course, I just put the objects' _renderable_ components in the vector of renderables. Subclassing like crazy is stupid, of course it is, I'm stupid but not that stupid.

//Original post deleted.

EDIT: Sean, I think I FINALLY got the idea. You mean that I should have only one class that represents the blueprint for _all_ entities, and a class for each component. And my GameObject should have two functions there, addComponent() and removeComponent() (for starters). And every time I want to add a new Monster, Player or Bunker, I just create a new GameObject object and add whatever components I need without making another class for player/monster/whatever, right?

EDIT 2: In order to add a component, I need to have a pointer to that component in the GameObject.

So you say that if I have 58 possible components, I need to create 58 empty pointers in my GameObject class, just in case it needs it? :huh:

EDIT 3: The other way people do it is to _not_ create an object for the entity, just store an ID that is based on bitmasking component IDs, but I'm going into Entity/Systems there... I really like the empty pointers design, the only thing is that it wastes memory. But one pointer is 4-6 bytes, my ram is 8 gigs, it's not a big deal, right? :huh:

EDIT 4: And if stuffing all references into GameObject is what you meant, then what's the difference between that and the update pattern I posted earlier?

Edited by bogosaur5000

Share on other sites
Inheritance and composition are tools I your toolbox. You shouldn't exclusively use one over the other any more than a builder should exclusively use mortar over bricks to build a house, it just wouldn't work...

Share on other sites

EDIT: Sean, I think I FINALLY got the idea. You mean that I should have only one class for entity, and that is the GameObject, and I should have two functions there, addComponent and removeComponent (for starters).

And if I want a Monster, instead of creating a monster class, I just create a new GameObject object, and add the components for monster. And the only thing that is left is for me to figure out how to do that in practice. But is this the main idea, having only _one_ class for entity, and _multiple_ classes for components, and then whenever I want a Player, Monster or Bunker,  I just create a new GameObject object and fill in the proper components? If you don't have time, just answer with yes or no.

You certainly _can_ use sub-classing to configure a GameObject, though I do think a function is a better approach.

EDIT 2: In order to add a component, I need to have a pointer to that component in the GameObject. So you say that if I have 58 possible components, I need to create 58 empty pointers in my GameObject class, just in case it needs it?

For a hobby game where you might only have 10 types of component, hard-coding the pointers into your GameObject is probably just fine. It doesn't cost you anything, it's easy to write, and _it just works_. Start there. Don't over-complicate things for no reason.

Now, if you have 58 components, then you perhaps need to start thinking about alternatives. A very simple approach here is to store your components on your GameObject with a map of some kind (say, a std::unordered_map). You can use the std::type_index (*not* type_info) of the component type. Something like this:

class GameObject {
unordered_map<type_index, unique_ptr<ComponentBase>> _components;

public:
template <typename T>
_components.insert(typeid(*component), std::move(component));
}

template <typename T>
T* findComponent() {
auto const it = _components.find(typeid(T));
return it != _components.end() ? static_cast<T*>(it->second.get()) : nullptr;
}
};

// ...game code...

Transform* transform = object->findComponent<Transform>();

// ...object initialization...

object->addComponent(make_unique<Model>(transform));

You can do the same without templates, too, though the templates make the usability much nicer.

There are even more sophisticated or more efficient ways to implement this, but again - do those matter for your engine? Probably not. Don't over-complicate things needlessly.

The one thing I will say, though - avoid querying components while the game is running. If you need an object's transform, store the pointer; don't call findComponent over and over again needlessly.

EDIT 3: The other way people do it is to not create an object for the entity, just store an ID, based on bitmasking component IDs, but I'm going into Entity/Systems there... I really like the empty pointers design, the only thing is that it wastes memory. But one pointer is 4-6 bytes, my ram is 8 gigs, it's not a big deal, right?

Yeah, that's the traditional ECS approach. I don't recommend it. It has some nice advantages but it getting it right is very difficult and getting it wrong is very easy. Simpler components architectures are much easier to write and use.

And no, RAM is not a big deal with GameObjects, unless you have a truly stupendous number of them. The cost of accessing or iterating over them is your enemy, not the memory usage. (Even on consoles; the modern devices give you enough wiggle room to not worry _too_ much about this kind of stuff.)

EDIT 4: How do I add a component that needs stuff from the previous component as an argument? My Armature component needs my Model component. Is this a sign of a bad design that I need to do this? (yes/no)

You can pass components in as parameters to other components, or have the component initialization logic query for other components, possibly using two passes to avoid order-of-construction issues:

simpleCreateMissile() {
// components are handed points to their dependencies, so they must be
// created in the proper order so they can initialize properly
object.transform = createTransform();
object.model = createModel(transform);
object.armature = createArmature(model);
}
complexCreateMissile() {
// components are created/loaded, but do not have their dependencies;
// this means the order is unimportant, but components cannot be fully
// initialized at this time - note that we might use a data file here to load
// the component types instead of hard-coding them so that our objects
// can be customized without recompiling the game

// all the components are present so they can now search for any
// dependencies and finish their initialization work
for (component : object.components)
component.initialize(this); // components use object->findComponent to find their dependencies
}

I again would keep it simple at first.

EDIT 5: And if stuffing all references into GameObject is what you meant, then what's the difference between that and the update pattern I posted earlier?

Storing components in a GameObject statically is different than querying those components in a loop multiple times every frame. :)

Say you spawn 1000 objects, and only 200 of them are visible/renderable (the others are invisible spawn points, or invisible trigger zones, or invisible sound sources, etc.). Do you think it's faster to iterate 1000 objects or 200? Do you think it's faster to iterate with an "if (has renderable)" in the loop or without that condition? Now, only 100 of those objects are dynamic physics bodies, so do you think looping over 1000 or 100 is better? Only 150 of them has AI, only 2 of them have player controllers, etc.

Here's the number one rule of optimization: not doing something will always run faster than doing it. :) The implication is that looping over objects that you don't need to loop over is inefficient.

Here's another important rule of optimization: don't put branches inside of loops if you can help it. That makes the CPU's branch predictor mispredict and results in frequent CPU instruction pipeline stalls.

Don't get me wrong: your original proposal _works_. Real shipping successful games have used very similar setups. I just don't recommend it; it seems easier/lazier but it can create more work in the long run. It works well only if your game has few types of components and relatively few objects.

Share on other sites

Do you think it's faster to iterate 1000 objects or 200? Do you think it's faster to iterate with an "if (has renderable)" in the loop or without that condition? Now, only 100 of those objects are dynamic physics bodies, so do you think looping over 1000 or 100 is better? Only 150 of them has AI, only 2 of them have player controllers, etc.

At these numbers you are no longer looking at times for the operations, you are looking at cache effects.

As an example, for a cache-friendly system it can be faster to simply walk across an 8,000 element sorted buffer and find the first match rather than to do a binary search where you would only hit 13 items.

Looping over 1000 objects in a cache-friendly way and doing cache-friendly operations will be far faster than hopping around to 100 items.

Also, a common mistake beginners make is to operate on single items.  That isn't what happens in good code.  Sure you could draw ONE thing, then draw ONE thing, then draw ONE thing, repeating doing ONE thing thousands of times.... Or you could bundle them all up together, make a single bundle with a huge batch of things, then call it ONE time.  The same is true with so many other systems.  As a quick study on rendering alone, here's a great writeup on GTA5 rendering. Note that they don't call a Render() or Draw() function on every item in the city.

The idea of putting a function on every single object that gets called every frame is tempting because it is easy, but it is terrible from a performance perspective. If you can process two or four or eight of them at once by doing them in parallel with SIMD instructions, you have just multiplied your performance by 2x or 4x or 8x.  If you can bundle up a bunch of them into a single combined process, you've eliminated all the extra overhead of all those function calls.

There are many variations on this theme.  Virtual functions that are rarely specialized are an enormous waste; you invested the cost of a major jump lookup and cache miss so that you could do zero work, sometimes doing this thousands of times per frame. Listeners that do nothing. Calling base classes that are empty. Repeating work that has already been done with idempotent calls. Sorting something that was already sorted, etc., etc.

While it is good to have a single instance where many things point to the real item, it can also be a good design to make specialized copies of data when that makes sense, too.  There are innumerable tools available if you look for them.  Inheritance and composition are two items among an enormous number of design options.

Share on other sites

for a cache-friendly system it can be faster to simply walk across an 8,000 element sorted buffer and find the first match rather than to do a binary search where you would only hit 13 items.

The benchmarking we've been doing for the flat_map proposal for the C++ committee does not reflect that folk wisdom, unfortunately. We've found it difficult to make linear search out-perform binary search past a dozen or so elements on real hardware (albeit in micro-benchmark-y cases, so take it with a grain of salt).

Note this also depends a bit on the key and whether the whole array fits in cache, how often you're searching this array, etc. Even a fragmented linked listed can be consistenly entirely in L1 cache, depending on usage patterns. :)

Looping over 1000 objects in a cache-friendly way and doing cache-friendly operations will be far faster than hopping around to 100 items.

Looping over 100 items in a cache-friendly way is faster than looping over 1000 in a cache-friendly way. ;)

Do less work, run faster.

To mesh that with frob's excellent advice: getting data out of main memory is more work for the hardware and getting data out of the CPU's caches is less work for the hardware. :)

Share on other sites

Imagine my character has the magic ability to become invisible, where he can go through walls and doesn't take hp.

So when the character is invisible, I would just like to remove the CollisionBox and Health out of the equation. With inheritance it's messy and ugly. But with composition, I can just remove the Health and the CollisionBox components when I'm invisible, and add them back when I'm visible, for example.

Removing components is clumsy. Being incorporeal is part of the state of the character, and the proper representation is as one or more fields in the Character class.

With a composition-based hierarchy of components, being incorporeal might or might not be split into, or copied into, component-level state (the character's CollisionBox is disabled, the Character's Health doesn't take damage from certain sources, the Character's Model switches to transparent textures).

The main challenge is not handling special cases (there's going to be a small and finite number of conditions like being incorporeal) but handling the state duration coherently in all components, presumably with the main entity (here a Character) handling timers etc.

Create an account

Register a new account

• Forum Statistics

• Total Topics
628754
• Total Posts
2984518

• 12
• 25
• 12
• 10
• 17