Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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:

  1. 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.
  2. 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?

share|improve this question
    
You don't really want to poll for an event to happen. An event only happens when it occurs. Doesn't Artemis allow for systems to communicate with each other? –  Sidar May 4 '13 at 5:10
    
It does, but only by coupling them using methods. –  Aeris130 May 7 '13 at 11:12
add comment

2 Answers 2

My advice here is coming from past experience on an RPG project where we used a component system. I will say that I hated working in that gameside code because it was spaghetti code. So I'm not offering much of an answer here, just a perspective:

The logic you describe for handling sword damage to a player... it seems one system should be in charge of all of that.

Somewhere, there's a HandleWeaponHit() function. It would access the player entity's ArmorComponent to get the relevant armor. It would access the attacking weapon entity's WeaponComponent to perhaps shatter the weapon. After computing final damage, it would touch the MovementComponent for the player to achieve the speed reduction.

As for wasted processing cycles... HandleWeaponHit() should only be triggered when needed (upon detecting the sword hit).

Maybe the point I'm trying to make is: surely you want a place in code where you can put a breakpoint, hit it, and then proceed to step through all the logic that is supposed to run when a sword hit occurs. In other words, the logic shouldn't be scattered throughout the tick() functions of multiple systems.

share|improve this answer
    
Doing it this way would make the hit() function baloon as more behavior are added. Let's say there's an enemy that falls down laughing every time a sword hits a target (any target) within its line of sight. Should HandleWeaponHit really be responsible for triggering that? –  Aeris130 May 7 '13 at 11:14
1  
You have a tightly enmeshed combat sequence so yes, hit is responsible for triggering effects. Not everything has to be broken out into little systems, let this one system handle this because it really is your "Combat System" and it handles... Combat... –  Patrick Hughes Jun 2 '13 at 19:42
add comment

It's a year old question but now I'm facing the same trubles with my home made game while studying ECS, thus some necromany. Hopefully it will end up in a discussion or at least few comments.

I`m not sure if it violates ECS concepts, but what if:

  • Add an EventBus to let Systems issue/subscribe to event objects (pure data in fact, but not a component I guess)
  • Create Components for each intermediate state

Example:

  • UserInputSystem fires an Attack event with [DamageDealerEntity, DamageReceiverEntity, Skill/Weapon used info]
  • CombatSystem is subscribed to it and calculates evasion chance for DamageReceiver. If evasion fails then it triggers Damage event with same parameters
  • DamageSystem is subscribed to such event and thus triggered
  • DamageSystem uses Strength,BaseWeapon damage, its type etc and writes it to a new IncomingDamageComponent with [DamageDealerEntity, FinalOutgoingDamage, DamageType] and attach it to the damage receiver Entity/Entities
  • DamageSystem fires a OutgoingDamageCalculated
  • ArmorSystem is triggered by it, picks up a receiver Entity or searches by this IncomingDamage aspect in Entities to pick up IncomingDamageComponent (last one could be probably better for multiple atacks with spread) and calculates armor and damage applied to it. Optionally triggers events for sword shattering
  • ArmorSystems removes IncomingDamageComponent in each entity and replaces it with DamageReceivedComponent with final calculated numbers that will afffect HP and Speed reduction from wounds
  • ArmorSystems sends an IncomingDamageCalculated event
  • Speed system is subscribed and recalculates the speed
  • HealthSystem is subscribed and decreases actual HP
  • etc
  • Somehow clean up

Pros:

  • System trigger each other providing intermediate data for complex chain events
  • Decoupling by EventBus

Cons:

  • I feel that I mix two ways of passing things: in event parameers and in the temporary Components. it might be a weak place. In theory to keep things homogeneous I could fire just enum events with no data so that Systems would find the implied parameters in the Entity's components by aspect... Not sure if it is Ok though
  • Not sure how to know if all the potentially interested SystemsHave processed IncomingDamageCalculated so that it could be cleaned up and let next turn happen. Maybe some kind of checks back in CombatSystem...
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.