So far the entity component systems I've used have worked mostly like Java's artemis:
- All data in components
- Stateless independent systems (at least to the degree that they don't require input on initialization) iterating over each entity that contains only the components that particular system is interested in
- All systems process their entities one tick, then the whole thing starts over.
Now I'm trying to apply this to a turn based game for the first time, with tons of events and responses that must occur in a set order relative to eachother, before the game can move on. An example:
Player A receives damage from a sword. In response to this, A's armor kicks in and lowers the damage taken. A's movement speed is also lowered as a result of getting weaker.
- The damage taken is what sets off the whole interaction
- Armor must be computed and applied to the incoming damage before the damage is applied to the player
- Movement speed reduction cannot be applied to a unit until after the damage has actually been dealt, since it is dependent on the final damage amount.
Events can also trigger other events. Reducing sword damage using armor can cause the sword to shatter (this must take place before the damage reduction is completed), which in turn can cause additional events in response to it, essentially a recursive evaluation of events.
All in all, this seem to lead to a few problems:
- Lots of wasted processing cycles: Most systems (save for things that always run, like rendering) simply doesn't have anything worthwile to do when it's not "their turn" to work, and spend most of the time waiting for the game to enter a valid work-state. This litters every such system with checks that keep growing in size the more states are added to the game.
- To find out if a system can process entities that is present in the game, they need some way to monitor other unrelated entity/system states (the systaem responsible for dealing damage needs to know if armor has been applied or not). This either muddles the systems with multiple responsibilities, or creates the need for additional systems with no other purpose but to scan the entity collection after each processing cycle and communicate with a set of listeners by telling them when it's okay to do something.
The above two points assume that the systems work on the same set of entities, that end up changing state using flags in their components.
Another way to solve it would be to add/remove components (or create entirely new entities) as a result of a single systems work to progress the games state. This means that whenever a system actually have a matching entity, it knows that it is allowed to process it.
This however make systems responsible for triggering subsequent systems, making it difficult to reason about the programs behaviour since bugs won't show up as the result of a single system interaction. Adding new systems also gets harder since they can't be implemented without knowing exactly how they affect other systems (and previous systems might have to be modified to trigger the states the new system is interested in), kinda defeating the purpose of having separate systems with a single task.
Is this something I'll have to live with? Every single ECS example I've seen have been real time, and it's really easy to see how this one-iteration-per-game-loop works in such cases. And I still need it for rendering, it just seems really unfit for systems that pause most aspects of itself every time something happens.
Is there some design pattern for moving the game state forward that is suitable for this, or should I just move all logic out of the loop and instead trigger it only when needed?