Coupling vs decoupling

Let’s say we have our good old ship that has hullpoints (zero indicates it is finally destroyed), syspoints (i.e. how operational it is, zero indicates it’s still there but can’t do anything like move or fire) and shieldpoints (on top of first two). We have two types of damage, one that affects only shield and hull, and one that affects only shield and system. Now the question is in damage control system (or systems). If we have them separated, it gives overhead in case, say, damage kills the whole shield and still has enough energy to damage hull/system. In this case we need to first kill shield and then recreate entity with remaining energy to be processed in corresponding system. If we process such a case in one common system - it’s just one more if-then block. The second question is that shield can be recharging in time. If we process it in some decoupled ShieldRecharge system - this contradicts the principle that there must be only one setter system for one type of component - cause we subtract from shield in damage system and add in recharge system. So which way is better?

For your use-case, if you know you will only have two types of ship damage then I think it’s reasonable to have them handled in one damage system.

However, modeling them as separate systems is fine also. You shouldn’t have to worry about the shields regenerating because that’s “next frame”. You just have to make sure your damage systems run together before the end of the frame… this will be an extremely common requirements for lots of things. It’s nice when you can avoid it but it’s always the case that you will have something that needs to run in order.

In the case where systems have an explicit ordering then it’s ok to have them mess with the same component. So the ship damage system can run first and adjust shields and ship damager then the system damage system can run second and do the same. (Pick an order that makes sense… but that one makes sense to me.) That’s in the case where each system would handle its own shield damage overflow.

Still another approach is to treat damage as two stages. In this case, all damage entities are initially treated in a generic way. They damage the shields and if there is any spill-over damage then they are converted to entities that will be picked up by the specific damage systems. Even if they are initially tagged with a damage type then that’s fine because it’s quite likely that you somehow use the same damage entity and just morph it. From a “Hit” component to a “Damage” component after it hits the shields. In this case, even if you let things run unlocked then everything is fine. It doesn’t matter if the shields suddenly regenerate themselves before the final damage is applied because technically that damage already happened. Plus we are at most talking about one frame delay (and system ordering prevents it from being an issue anyway but it’s no longer critical.)

Both ways are ok… it just depends where you want your flex points to be. If shields can potentially absorb hit damage in different ways then it might be best to let each damage system do it’s own shield adjustments… at the cost of requiring a specific ordering/synching of the systems to avoid them doing strange things to the shield value.

Thanks for the clarifications, just one more tiny question - by ordering you mean ordering in which we attach systems or anything else i somehow missed?

Presumably your systems have some kind of update method. (I don’t know how you’ve implemented them so I’m just guessing.) What I mean by ordering is the order in which the update methods are called.

Just now, after spending couple of days on refactoring existing things, I finally realized what “next frame” means :slight_smile: Indeed, sometimes you want to set different components twice in one single update, and then strange things become happening. But what I learned is that if I need for (Entity e : entities) twice in one update - it’s a sign of bad design. Omg, and I haven’t even started multi-threading yet!