Morgemil Part 17 – Engine Rework Chapter 2

Here’s where I left off. Everything is made up of behaviors.

interface ICastSpell
  void Behave(Spell spell);
class DungeonMonster
  public IMove MoveBehavior {get; set; }
  public IAttack AttackBehavior {get; set; }
  public ICastSpell SpellBehavior {get; set }
  public void Move(Direction direction)
  public void Attack(Direction direction)
  public void CastSpell(Spell spell)
class LightMold: DungeonMonster
  public LightMold()
    MoveBehavior = new Immobile();
    AttackBehavior = new Defenseless();
    SpellBehavior = new EvilSpellCast(); //LightMolds cast evil spells apparently.
class Goblin: DungeonMonster
  public Goblin()
    MoveBehavior = new Mobile();
    AttackBehavior = new Defensive();
    SpellBehavior = new NoSpells(); //Goblins have no magical aptitude

Remember, the idea is composition. Composition should provide flexibility. I plan to do it through the use of entities. So here’s my implementation of an entity:

type EntityId = EntityId of int
type EntityType = 
  | Person
  | Door
  | Stairs
  | Object
type Entity = 
  { Id : EntityId
    Type : EntityType }

It is an integer (technically a single case discriminated union) with a bit of immutable meta-data.

An entity has nothing. All info about an entity is contained in components.

type PositionComponent = 
  { EntityId : EntityId
    Position : Vector2i
    Mobile : bool }
type PlayerComponent = 
  { EntityId : EntityId
    IsHumanControlled : bool }
type ResourceComponent = 
  { EntityId : EntityId
    ResourceAmount : double }

Entities and components are linked together only by the entity’s ID. Certainly a far departure from Object-Oriented convention. But does this remind you of anything?

Relational databases are fond of using an integer as a primary key to make nice foreign key. So the entity and components above could look like this
This has a couple benefits:

  • Composition of behavior through whether an entity has a component(s) or not.
  • No longer have to maintain giant object hierarchies
  • Systems can operate on isolated information. Example: Field-of-view, collision detection, and spatial operations in general should only need to operate on a collection of PositionComponents. They don’t care what other components an entity may have.
  • Serialization is much easier. This is important when loading or saving game state, sending game state over network, and logging.

There are other benefits as well, but those will become apparent over time and examples. Of course there are drawbacks too, but those will become apparent with time as well.