I'm developing a 2D roguelike with an Entity Component System (ECS) and I've been struggling with this question a lot the past week. For example, let's say you have various effects that occur when an entity spawns, dies, collides with another entity, etc. Where should these effects be coded? I see two main possibilities:
In the entity itself. Example pseudocode:
let effectsComponent = new EffectsComponent(); effectsComponent.onHit = [ damage(10), deleteSelf() ]; effectsComponent.onDeath = [ playSound("player-death.mp3") ]; // Effects system for (let effect of ...
In a system. Example pseudocode:
// Damage system for (let event of scene.events.query<CollisionEvent>()) { if (event.entity1 is bullet and event.entity2 is player) { event.entity2.damage(10); event.entity1.delete(); } } // Sound system for (let event of scene.events.query<DeathEvent>()) { switch (event.entity.type) { case ET.Player: playSound("player-death.mp3"); break; } }
I can think of numerous pros and cons for each approach. The first approach can likely cut down on some conditionals because since we are defining it on the entity itself, we already know its "type" already, so the only thing we would have to worry about is the type of the receiving entity. As such, it's likely more terse to code in the first manner.
However, the second approach might be more "proper" within the context of an ECS. That is, you could argue that it is not the responsibility of an entity to describe its behavior. Components should only hold state, and not behavior, and it's a short road to spaghetti when you begin mixing in behavior and state within an entity definition.
In addition, many events may not even have a receiver
or target
entity, so regardless in some situations we'll have encode it into the system's functionality regardless. And if that is the case, then why not just be consistent and always make systems handle this sort of thing?
Lastly, philosophically, it kind of feels like systems should be responsible for handling the interaction response of two entities. As an example, with the first approach, should the player entity or the bullet entity encode the behavior response for when they collide with each other? It's unclear. Then again, it also feels like entities should describe their data, and things like sound effects should likely be encoded within an entity component instead of being delineated within a system.
In other words, I'm very unsure of how to handle this. What is considered better design here? Should components be responsible for holding this interaction / event data, or should systems?
CollisionSystem
simply detects whether or not there is a collision between two entities. Are you saying it should also determine what sorts of entities they are and then create events other than justCollisionEvents
? \$\endgroup\$