Managing a World of Entities in XNA

A structure that I find works very well when managing entities in games is the world/entity/component pattern. Entities in the world are nothing more than collections of components, where the components have the responsibility to "do something" with the entity. The Entity just gives you a convenient place for common information (global transform, say), and specialized data goes into each component.

This way, you can compose components for different behaviors (rendering, audio, animation, user control, AI, explosions, particle systems, etc) and create entirely new kinds of entities out of an existing palette of components.

class World {
  List<Entity> entities_ = new List<Entity>();
  List<Entity> toAdd_ = new List<Entity>();
  List<Entity> toRemove_ = new List<Entity>();
  public World() {}
  public void AddEntity(Entity ent) {
    toAdd_.Add(ent);
  }
  public void RemoveEntity(Entity ent) {
    toRemove_.Add(ent);
  }
  public void Update() {
    int i = 0, n = toAdd_.Count;
    for (; i != n; ++i) {
      Entity ent = toAdd_[i];
      entities_.Add(ent);
      ent.OnAttach(this);
    }
    toAdd_.RemoveRange(0, n);
    i = 0; n = toRemove_.Count;
    for (; i != n; ++i) {
      Entity ent = toRemove_[i];
      entities_.Remove(ent);
    }
    for (i = 0, n = entities_.Count(); i != n; ++i)
      entities_[i].Update();
  }
}
 
class Component {
  string id_;
  protected Entity entity_;
  public Component(string id) {
    id_ = id;
  }
  public string ID { get { return id_; } }
  public Entity Entity { get { return entity_; } }
  internal void OnAttach(Entity ent) {
    entity_ = ent;
    LocalSetup();
  }
  protected virtual void LocalSetup() {}
  internal void Update() {
    LocalUpdate();
  }
  protected virtual void LocalUpdate() {}
}
 
class Entity {
  World world_;
  List<Component> components_ = new List<Component>();
  public Entity() {
  }
  public void AddComponent(Component comp) {
    components_.Add(comp);
    if (world_ != null)
      comp.OnAttach(this);
  }
  internal void OnAttach(World world) {
    world_ = world;
    for (int i = 0, n = components_.Count; i != n; ++i)
      components_[i].OnAttach(this);
  }
  public Component FindComponent(string id) {
    for (int i = 0, n = components_.Count; i != n; ++i)
      if (components_[i].ID == id) {
        return components_[i];
  }
  internal void Update() {
    for (int i = 0, n = components_.Count; i != n; ++i)
      components_[i].OnUpdate();
    if (pos_ != newPos_) {
      pos_ = newPos_;
      if (OnMoved != null)
        OnMoved(this, newPos_);
    }
  }
  internal Vector3 newPos_;
  internal Vector3 pos_;
  public Vector3 Position { get { return pos_; } set { newPos_ = value; } }
  public event EntityMoved OnMoved;
}
public delegate void EntityMoved(Entity ent, Vector3 pos);
 
 
class RenderableComponent : Component, SceneGraphNode {
  SceneGraphModel model_;
  public RenderableComponent(string model)
    : base("renderable")
  {
    model_ = SceheGraphModelLoader.Load(model);
  }
  internal override void LocalSetup() {
    Entity.OnMoved += new EntityMoved(this.Moved);
  }
  void Moved(Entity ent, Vector3 pos) {
    SceneGraph.NodeMoved(this, pos);
  }
  // an assumed callback from your scene graph
  public overrid void DrawSceneGraphNode(DrawInfo info) {
    model_.Draw(info);
  }
}
 
class ControllableComponent : Component {
  // Let's assume "Controller" is your controller wrapper.
  Controller controller_;
  public ControllableComponent(PlayerIndex player) {
    controller_ = Controller.ForPlayer(player);
  }
  public override void LocalUpdate() {
    if (controller_.Gas) {
      Entity.Position = Entity.Position + Vector3.Forward;
    }
    if (controller_.Right) {
      Entity.Position = Entity.Position + Vector3.Right;
    }
    if (controller_.Left) {
      Entity.Position = Entity.Position + Vector3.Left;
    }
  }
}
 
void Setup()
{
  // create a world
  world_ = new World();
  // create a track
  track_ = new Entity();
  track_.AddComponent(new RenderableComponent("trackmodel"));
  world_.AddEntity(track_);
  // create a mover
  mover_ = new Entity();
  mover_.AddComponent(new RenderableComponent("movermodel"));
  mover_.AddComponent(new ControllableComponent(PlayerIndex.One));
  world_.AddEntity(mover_);
}
 
void Update()
{
  // automatically update all entities in the world
  world_.Update();
}
 
void Render()
{
  // let's assume you have a scene graph...
  SceneGraph.Render();
}

Comments

Component communication

I have been reading a few articles regarding this design pattern and it seems as though the biggest challenge is how components relay messages within the entity. For example -- if in a controller component a player pushes the "accellerate" button, force is applied by the physics component to the entity which ultimately updates the entities position. How do you get these to talk to each other without them being too dependent upon each other's existence? BTW -- thanks so much for such an insightful article!!!!

jwatte's picture

For some common things, I've

For some common things, I've found that putting them in the Entity makes most sense. Position, Orientation, and velocities go there for me. This has the draw-back that my "rules" entity (which runs overall game logic) has a position, even though it doesn't have a physical presence, but I can live with that.

For slightly less common things, I define interfaces. There's an IPhysicsObject interface, which defines properties like Mass, and can accept force and torque. This component delegates to the physics library. Then I have a Control object (not an interface) which reads the input library, and applies the appropriate forces to the IPhysicsObject. There's a different Control object for vehicles than for avatars, say.
The Entity class has a FindComponent(Type) method, and a FindComponent(name) method, although 99% of the time I use the Type flavor. Name is there to separate multiple instances of the same type (particle effects, say) if they need some control information.

Some other things that are common: there are two update phases. The "update" phase allows all components to read the previous state of the entity, and write the new state. However, you can't read the new state. The "commit" phase copies the new state to old state, and allows reading the new state (for forwarding to a scene graph, etc). During edit mode, the Update never gets called (as I don't want objects to move around while being edited) but the commit function keeps getting called (to commit changes made in the editor).

The pattern is generally that all components are inert containers of parameter information until they are attached to an entity. Inside the OnAttached callback, the component configures itself, loads assets, and finds pointers to other components (so they are cached inside the Update calls). Inside OnDetached, the components un-register/un-load themselves again. I add all the components to the entity first, and then call OnAttached on each of them, so that they can actually find the other components even if there is an ordering difference.

And all my component configuration is through an XML scene file, rather than in code, and I have a scene editor/inspector control that allows me to tweak objects at runtime, and save out a new XML file. But that's kind-of more code than fits in a single article :-)

Component logic

So here's a couple more questions... :D
Do your components contain data and logic, or do you have various subsystems to handle the logic? It would appear from what I could gather above that the components do. If I recall correctly on one of your posts on the XNA creator's site that you mentioned having different "worlds" (i.e. physics, collisions, graphics) which almost sounds like a subsystem approach and am wondering if that applies at all to your example here.

You mentioned the two update "phases" above and I was a little curious on where those phases get implemented? Are they two seperate methods contained within the components? I guess I'm wondering kind of how that would look in code.

Sorry for all the ???s -- I'm thoroughly interested in using this approach and have been reading lots of articles (i.e. "Evolve Your Hierarchy" and the T-Machine article, etc..) and posts over on gamedev.net but very few have examples in c#... and even though I can sort of read c++, I know I'm missing a lot of the fine details due to my lack of good familiarity with that language. Thanks again!!!!!!!

jwatte's picture

I'm using subsystems for

I'm using subsystems for graphics, sound, physics and special effects. However, I put the game logic in the actual world/entity system.

Update and Commit are methods on the entity components. In editor mode, Update() is not called, but Commit() is; this allows objects to update themselves in the scene graph when moved through the editor, without having to run the physical simulation (which is polled and controlled mainly out of Update()). In my system, all entities are first Update()-ed, which Update()-s the components within the entity. Then, as a separate pass, all entities are Commit()-ed, which Commit()-s the components within the entity. This way, all entities and components only depend on the state of other entities/components for the same update cycle/time step, because of the rules for reading/writing old/new state, and copying the state after update but before commit.

I'm thinking that the component system could probably be "purified" by defining events for the update, commit and perhaps pre-render events (although that can come from the scene graph). Then, components that don't need to do anything, don't need to get called, and I'd save some on overhead. The drawback would be slightly more code to register yourself for the events you needed in the component.

Finally, the components are there for editing: in my world editor, I can select an entity (using the entity list, or the world view clicking if it's collidable). When selected, the entity properties go on top of the window, followed by the properties for each component, each in their own collapsible roll-out panel. There's also a little bit of UI to add or remove components to an existing entity. All in all, it all comes together pretty well -- it's certainly a structure that's working well for me for now, even though it takes some short-cuts (like making position/orientation entity properties, rather than component properties, and making all components have update and commit functions).

Update and Commit

So regarding the old/new states -- does each component have two copies of each of its variables - ? -- example: life component... does this component have an int oldLife and int newLife variable such that in it's Update() method, it and other components that require its data are reading and performing operations on oldLife and then in Commit(), the life component takes the value in oldLife and publishes it to newLife?

How does your physics simulator Update figure into this, since in the physics libraries I've seen this is handled by one call to the physics sim's Update() method? In my case, I'm working with Farseer which just uses one Update() call per time step to iterate through each of the bodies and geoms that are registered with it -- how would this one function figure into Update() and Commit() within the entities with Physics components?

jwatte's picture

That's up to each component.

That's up to each component. Currently, the Entity double-buffers the "well known" values, which are position, orientation, and their derivatives.

The update from physics subsystem to entity subsystem happens in the Update() call, where the physics component will read the simulation outcome from the physics subsystem, and copy it into the entity state. This means the physics is run separate from the entity system (and, in fact, could be run in another thread entirely, with the proper sync points).

Is that something like

jwatte's picture

Yes. There are, in fact, a

Yes. There are, in fact, a lot of descriptions of component systems out there, including in some volumes of the Game Programming Gems book series. It's the way that modern game design is moving, for several reasons:
- Specialized systems need specialized data structures. Rendering does not use the same data as collision, which doesn't use the same data as AI. Putting everything in the scene graph, like a lot of people did in the '90s, no longer works at all.
- Class inheritance is not flexible enough to mold to express new gameplay entities as they are created.
- Designers want to be able to create new entities (a "talking door" puzzle, say) without necessarily involving engine programmers.