13
\$\begingroup\$

I'm designing a game engine for a top-down multiplayer 2D shooter game, which I want to be reasonably reuseable for other top-down shooter games. At the moment I'm thinking about how something like an entity system in it should be designed. First I thought about this:

I have a class called EntityManager. It should implement a method called Update and another one called Draw. The reason for me separating Logic and Rendering is because then I can omit the Draw method if running a standalone server.

EntityManager owns a list of objects of type BaseEntity. Each entity owns a list of components such as EntityModel (the drawable representation of an entity), EntityNetworkInterface, and EntityPhysicalBody.

EntityManager also owns a list of component managers like EntityRenderManager, EntityNetworkManager and EntityPhysicsManager. Each component manager keeps references to the entity components. There are various reasons for moving this code out of the entity's own class and do it collectively instead. For example, I'm using an external physics library, Box2D, for the game. In Box2D, you first add the bodies and shapes to a world (owned by the EntityPhysicsManager in this case) and add collision callbacks (which would be dispatched to the entity object itself in my system). Then you run a function which simulates everything in the system. I find it hard to find a better solution to do this than doing it in an external component manager like this.

Entity creation is done like this: EntityManager implements the method RegisterEntity(entityClass, factory) which registers how to create an entity of that class. It also implements the method CreateEntity(entityClass) which would return an object of type BaseEntity.

Now comes my problem: How would the reference to a component be registered to the component managers? I have no idea how I would reference the component managers from a factory/closure.

\$\endgroup\$
4
  • \$\begingroup\$ I don't know if perhaps this is meant to be a hybrid system, but it sounds like your "managers" are what I've generally heard termed as "systems;" i.e. the Entity is an abstract-ID; a Component is a pool of data; and what you term a "manager" is what's generally termed a "System." Am I interpreting the vocabulary correctly? \$\endgroup\$
    – BRPocock
    Dec 22, 2011 at 21:24
  • \$\begingroup\$ My question here may be of interest: Game Components, Game Managers and Object Properties \$\endgroup\$ Jan 11, 2012 at 8:11
  • \$\begingroup\$ Take a look at gamadu.com/artemis and see if their methods answer your question. \$\endgroup\$ Jun 9, 2012 at 22:00
  • 1
    \$\begingroup\$ There is no one way of designing an entity system as there's little consensus over it's definition. What @BRPocock describes and also what Artemis uses hes been described more in depth on this blog: t-machine.org/index.php/category/entity-systems together with a wiki: entity-systems.wikidot.com \$\endgroup\$
    – user8363
    Aug 12, 2012 at 9:50

3 Answers 3

6
\$\begingroup\$

Systems should store a key value pair of Entity to Component in some sort of Map, Dictionary Object, or Associative Array (depending on language used). Furthermore, when you create your Entity Object, I wouldn't worry about storing it in a manager unless you need to be able to unregister it from any of the Systems. An Entity is a composite of components, but it shouldn't handle any of the component updates. That should be handled by the Systems. Instead treat your Entity as a key that is mapped to all components it contains in the systems, as well as a communication hub for those components to talk to each other.

The great part about Entity-Component-System models is that you can implement the ability to pass messages from one component to the rest of an entity's components quite easily. This allows a component to talk to another component without actually knowing who that component is or how to handle the component it's changing. Instead it passes a message and lets the component change itself (if it exists)

For instance, a Position System would not have much code in it, only keeping track of Entity Objects mapped to their Position Components. But when a position changes, they can send a message to the Entity involved, which in turn is handed off to all of that entity's components. A position changes for what ever reason? Position System sends Entity a message saying that the position changed, and somewhere, that entity's image rendering component gets that message and updates where it'll draw itself next.

Conversely, A Physics System needs to know what all of it's objects are doing; It must be able to see all world objects to test collisions. When a collision happens, it updates the Entity's direction component by sending some sort of "Direction Change Message" to the entity instead of referring to the Entity's component directly. This decouples the manager from needing to know how to change directions by using a message instead of relying on a specific component being there (which it may not be there at all, in which case the message would just fall on deaf ears instead of some error occurring because an expected object was absent).

You'll notice a huge advantage from this since you mentioned you have a Network Interface. A Network Component would listen to all messages coming in that everyone else should know about. It loves the gossip. Then when the Network System updates, the Network components send those messages to other Network Systems on other client machines, which then resend those messages to all the other components to update player positions, etc. Special logic might be needed so that only certain entities can send messages over the network but that's the beauty of the System, you can just have it control that logic by registering the right things to it.

In short:

Entity is a composition of Components that can receive messages. Entity can receive messages, delegating said messages to all of their components to update them. (Position changed Message, Speed Change Direction, etc) It's like a central mailbox that all components can hear from each other instead of talking directly to each other.

Component is a small part of an Entity that stores some state of the entity. These are able to parse certain messages and throw other messages out. For instance, a "Direction Component" would only care about "Direction Change Messages" but not "Position Change Messages". Components update their own state based on messages, and then update other components' states by sending messages from their System.

System manages all components of a certain type, and is responsible for updating said components each frame, as well as dispatching messages from the component's they manage to the Entities that the Components belong to

Systems could be able to update all of their components in parallel, and store all messages as they go. Then when execution of all Systems' update methods complete, you ask each system to dispatch their messages in a specific order. Controls first possibly, followed by Physics, followed by direction, position, rendering, etc. It matters which order they are dispatched in since a Physics Direction Change should Always out weigh a control based direction change.

Hope this helps. It's a hell of a Design Pattern, but it's ridiculously powerful if done right.

\$\endgroup\$
0
\$\begingroup\$

I'm using a similar system in my engine and the way I've done it is each Entity contains a list of Components. From the EntityManager, I can query each of the Entities and see which ones contain a given Component. Example:

class Component
{
    private uint ID;
    // etc...
}

class Entity
{
    List<Component> Components;
    // etc...
    public bool Contains(Type type)
    {
        foreach(Component comp in Components)
        {
            if(typeof(comp) == type)
                return true;
        }
        return false;
    }
}

class EntityManager
{
    List<Entity> Entities;
    // etc...
    public List<Entity> GetEntitiesOfType(Type type)
    {
        List<Entity> results = new List<Entity>();
        foreach(Entity entity in Entities)
        {
            if(entity.Contains(type))
                results.Add(entity);
        }
        return results;
    }
}

Obviously this isn't the exact code (you'd actually need a template function to check for different component types, rather than using typeof) but the concept is there. Then you could take those results, reference the component you're looking for, and register it with your factory. This prevents any direct coupling between Components and their managers.

\$\endgroup\$
12
  • 3
    \$\begingroup\$ Caveat emptor: at the point at which your Entity contains data, it's an object, not an entity… One loses most of the paralelizing (sic?) benefits of ECS in this structure. "Pure" E/C/S systems are relational, not object-oriented … Not that it's necessarily "bad" for some case(s), but it's certainly "breaking the relational model" \$\endgroup\$
    – BRPocock
    Dec 22, 2011 at 21:21
  • 2
    \$\begingroup\$ I'm not sure I understand you. My understanding (and please correct me if I'm wrong) is the basic Entity-Component-System has an Entity class which houses Components and might have an ID, name, or some identifier. I think we may have a misunderstanding in what I mean by "type" of Entity. When I say Entity "type," I'm referring to the types of Component. That is to say, an Entity is a "Sprite" type if it contains a Sprite Component. \$\endgroup\$
    – Mike Cluck
    Dec 23, 2011 at 0:28
  • 1
    \$\begingroup\$ In a pure Entity/Component system, an Entity is usually atomic: e.g. typedef long long int Entity; a Component is a record (it might be implemented as an object class, or just a struct) that has a reference to the Entity to which it's attached; and a System would be a method or collection of methods. The ECS model isn't very compatible with the OOP model, although a Component can be a (mostly) data-only Object, and a System a code-only singleton Object whose state lives in components... although "hybrid" systems are more common than "pure" ones, they lose many of the innate benefits. \$\endgroup\$
    – BRPocock
    Dec 23, 2011 at 2:44
  • 2
    \$\begingroup\$ @BRPocock re "pure" entity systems. I think an entity as an object is perfectly fine, it doesn't have to be a simple id. One thing is the serialized representation, another the in-memory layout of an object / a concept / an entity. As long as you can maintain data-drivenness, one shouldn't be tied to non-idiomatic code just because it's the "pure" way. \$\endgroup\$
    – raine
    Mar 11, 2012 at 15:21
  • 1
    \$\begingroup\$ @BRPocock this is a fair warning, but for "t-machine"-like entity systems. I understand why, but those are not the only ways to model component-based entities. actors are an interesting alternative. I tend to appreciate them more, especially for purely logical entities. \$\endgroup\$
    – raine
    Mar 12, 2012 at 21:55
0
\$\begingroup\$

1) Your Factory method should be passed a reference to the EntityManager that called it (I'll use C# as an example):

delegate BaseEntity EntityFactory(EntityManager manager);

2) Have CreateEntity also receive an id (e.g. a string, integer, it's up to you) besides the class/type of the entity, and automatically register the created entity on a Dictionary using that id as a key:

class EntityManager
{
    // Rest of class omitted

    BaseEntity CreateEntity(string id, Type entityClass)
    {
        BaseEntity entity = factories[entityClass](this);
        registry.Add(id, entity);
        return entity;
    }

    Dictionary<Id, BaseEntity> registry;
}

3) Add a Getter to EntityManager to get any entity by ID:

class EntityManager
{
    // Rest of class omitted

    BaseEntity GetEntity(string id)
    {
        return registry[id];
    }
}

And that's all you need to reference any ComponentManager from within your Factory method. For instance:

BaseEntity CreateSomeSortOfEntity(EntityManager manager)
{
    // Create and configure entity
    BaseEntity entity = new BaseEntity();
    RenderComponent renderComponent = new RenderComponent();
    entity.AddComponent(renderComponent);

    // Get a reference to the render manager and register component
    RenderEntityManager renderer = manager.GetEntity("RenderEntityManager") as RenderEntityManager;
    if(renderer != null)
        renderer.Register(renderComponent)

    return entity;
}

Besides Id you can also use some sort of Type property (a custom enum, or just rely on the language's type system), and create a getter that returns all BaseEntities of a certain type.

\$\endgroup\$
11
  • 1
    \$\begingroup\$ Not to be pedantic, but again… in a pure Entity (relational) system, entities have no type, except that imparted to them by virtue of their components… \$\endgroup\$
    – BRPocock
    Dec 22, 2011 at 21:22
  • \$\begingroup\$ @BRPocock: Could you create an example that follows the pure virtue? \$\endgroup\$
    – Zolomon
    Mar 11, 2012 at 11:11
  • 1
    \$\begingroup\$ @Raine Perhaps, I don't have first hand experience with this, but that's what I read. And there are optimizations you can implement to reduce the time spent looking up components by id. As for cache coherence, I think it makes sense since you're storing data of the same type contiguously in memory, especially when your components are lightweight or simple properties. I've read that a single cache miss on the PS3 can be as expensive as a thousand CPU instructions, and this approach of storing data of similar type contiguously is a very common optimization technique in modern game development. \$\endgroup\$ Mar 11, 2012 at 16:16
  • 2
    \$\begingroup\$ In ref: “pure” entity system: the Entity ID is typically something like: typedef unsigned long long int EntityID;; the ideal is, that each System can live on a separate CPU or host, and only require to fetch components that are relevant to / active in that System. With an Entity object, one might have to instantiate the same Entity object on each host, making scaling more difficult. A pure entity-component-system model splits processing across nodes (processes, CPUs, or hosts) by system, rather than by entity, typically. \$\endgroup\$
    – BRPocock
    Mar 12, 2012 at 21:11
  • 1
    \$\begingroup\$ @DavidGouveia mentioned “optimizations…looking up entities by ID.” In fact, the (few) systems I've implemented this way, tend to not do so. More often, select Components by some pattern indicating that they're of interest to a particular System, using Entities (ID's) only for cross-component Joins. \$\endgroup\$
    – BRPocock
    Mar 12, 2012 at 21:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .