4
\$\begingroup\$

I've been working on how to build some of my game systems using components and systems. I'm having a little trouble following the approach that components should just be bags of data and systems should implement the logic. It'd seem for this to be true you have to limit the complexity of the components or somehow make the system aware of all possible complexity.

For example, I have equipment in my game that characters can equip. Equipment has an "Item" component that has an item name, description, value etc. and allows me to identify it as an item for the purpose of character inventory, etc. That's simple enough.

Here's my problem though. Equipment also needs to be "equippable". Originally, I implemented it as something like this:

class EquipComponent : public Component
{
public:
     virtual bool equip(Entity* character) = 0;
     virtual bool unequip(Entity* character) = 0;
};

then I'd export this class to my scripting engine, and I'm free to have equip/unequip do whatever I want to the character they're being equipped too.

When I try to implement this component as just a bag of data, it just seems so limited. If I want the equipment to increase stats, I can add an array of stat adders/multipliers. If I want to have equipment add status effect resistances, I can add a table for that. If a piece of equipment has different effects for different weatrers, now I have to add data on a per user basis. Suddenly my simple bag of data has gotten massive. I could split it into seperate components, but now my system needs to be aware of every possible component that can change how an item is equipped.

I can see problems like this popping up in a lot of potential components/systems, so I was wondering how one can decouple the components and systems? Am I thinking too rigidly that most component logic should be handled by systems? As much as this is a learning experience, I would like to have something I can use for more than one project and that has good scalability.

Any insight or advice would be appreciated!

\$\endgroup\$
  • \$\begingroup\$ It seems to me like you're running into the expression problem. \$\endgroup\$ – Maxpm Oct 10 '13 at 15:21
  • \$\begingroup\$ OO-programming is all about encapsulating data and logic together. So yeah, if your stuck trying to separate things, put your logic inside your components, there's nothing wrong about it. Whatever works for you. \$\endgroup\$ – Laurent Couvidou Oct 10 '13 at 21:44
5
\$\begingroup\$

There are several potential problems here.

First, not all components need the idea of systems as from "entity component systems." Much simpler and more obvious designs are both quite possible and more "real-world" (I've seen major AAA engines using the simpler approaches; I've never in my life seen a real engine using pure ECS). Components can be regular objects with methods and behavior and event handlers and all the other stuff you'd expect. There are places where an ECS-like approach makes sense, but those are not everywhere. I'd even argue that they are never needed as most of the performance-sensitive systems in the game have parallel hierarchies

Second, you should avoid making tons of components that are tied together functionally. If every item is equippable and every equippable is an item, there is zero purpose to making them separate components. Just merge the interfaces/features. Experience across a number of significant games with component-based engines has led me at least to lean towards coarser components rather than granular components (obviously it's a balancing act).

Third, the problem you're running into is not directly a problem with your ECS-based design. Things like equipment can have data that describes effects and then the system can use that data to apply it to characters. This is one of the more awkward areas of pure-ECS since you end up with a system that depends on its own components and then depends on another system/component (which somewhat eliminates the data-oriented nature of ECS). You could also implement equipment with events. E.g., the item triggers an "Add 10 Strength" event and pushes that into an event queue. Then the character system processes that event queue. For more detail on how such an event system might work, see the article series starting at this BitSquid blog entry. Yes, you can add "an array of stat modifiers" but you can take this a step further to include an array of effects in a bytecode-like data layout, very efficient to apply (but you'll need more complicated tools to edit and visualize the data).

I really would just recommend dropping the whole systems approach and using a simpler component model. Development gets easier and faster and it's unlikely that any loss of performance is going to hurt you noticeably (and if by some off chance you're working at DICE on Battlefield 5 or something, you can get most of the data-oriented benefits in the areas most needing it without using a pure ECS everywhere).

\$\endgroup\$

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.