Is often read that in entity component system pattern we should treat components just as a passive data structure with no logic at all, this way we follow to a data oriented design approach with efficient usage of cache memory and gain performance.
I was developing a simple game using this rule and when the game was getting bigger I start facing some serious code smells such as repeated code in systems, let's suppose its a shooter to illustrate an example. In this shooter I had bullets being fired so I created a BulletComponent and a BulletSystem that handles when it collides and make some damage and if don't collide with anything the bullet dissapear in five seconds. Then I wanted some explosives so I created the ExplosiveComponent and ExplosionSystem, once the explosive is placed it explodes in ten seconds. At this point we can notice the first repeated code between systems then we can make an abstraction and we create a DurationComponent and a DurationSystem so the bullet and the explosive contains it with the time it should last.Then I realized that when the explosive should explode I want to create some particle effect in the area so this abstraction is no longer valid as I want to perform differents actions when time runs out, but if I do as at the beginning I have the repeated code between systems (ugh!). This example is simple but I'm facing this with more complex things like AI, or reacting to collisions.
One solution I came to this is that I really wanted an ActionComponent with a ActionSystem that executes the action contained in the component but this way I'm breaking that components only contains data and they should not have logic! this is more an 'hybrid' approach. But if you start thinking deeply the ActionSystem is very generic and you can almost do anything with it so it's hard to determine whether a system is necessary or not. The same can be applied to collisions, instead of having lots of systems with logic for different entities colliding, you can just have a CollisionHandlerComponent with the logic on it for each entity.
I found the following advantages making generic systems like this:
- Higher flexibility (you can customize each entity easily)
- No repeated code
- Less systems (more performance?)
But as I said the main disadvantage is that is really confusing if a system is needed as you can stick logic to components.
Is it wrong to follow this sort of hybrid ecs? If yes, what would be your approach to the example without repeating code in systems?