I'm using a hybrid of DDD (domain-driven development) and an entity-component system. That is to say:
- I have an
Entity
class with a list ofComponent
s, and the ability to add/remove/get components - I have
component
instances likeHealthComponent
(health and is-alive),DrawComponent
(position + display), etc. System
instances (likeDrawSystem
) that find a bunch of components and operate on them
I also have "domain objects" like Player
and Monster
, which subclass Entity. Their constructors usually add a bunch of components.
Since I'm a fan of the DDD idea of objects represent business/game entities, I model my classes around that. For a roguelike, my Player
class has methods like:
Attack(Monster)
GetX
andGetY
(delegates to the position component)LevelUp
RegenerateHealth
- And others
It seems to me that the components are a white-box internal detail; they shouldn't be known to any outside objects. In fact, domain objects should operate on other domain objects (eg. Player.Attack(Monster)
).
Most (if not all) of my actual game code operates on entities, not components. My tests usually do something like:
- Create an entity
- Grab a certain component
- Verify that it meets expectations
In general, this raised a question in my mind: isn't this a violation of encapsulation? Aren't components just an internal implementation detail of entities (that could change or disappear at any time)?
On the other hand, I have a lot of delegation, which seems useless (like Player.getX()
is just Player.get(DisplayComponent).getX()
).
This seems confusing. Can someone provide some clarity? What is the right mix of DDD, encapsulation, and entity/component composition?
RegenerateHealth
on the player. Entities need to attack, because it's a combination of position components (are you in range?) and health components (are you alive?) and other attributes (strength, etc.) \$\endgroup\$Entity
except categorical components, wherein all the real logic exists. You are meant to encapsulateRegenerate
within aHealth
component which describes both state and functionality relating toEntity
health. Now when anything affects health, whether it be internal or external to theEntity
itself (including unit tests), these may simply be accessed by referencing thatEntity
's appropriate component property, in this case,Entity.Health
. \$\endgroup\$