Skip to main content
GameDev.net gamedev.net
🔒 Locked

Entity Systems design question

Started by wolfscaptain Jul 30, 2011 at 9:35 PM 8 replies 3.4k views
Original Post
wolfscaptain
wolfscaptain
I really liked the idea of a pure entity system like described in this article series.

Now, implementing the entity manager itself is very easy.
The hard part for me is designing interaction between components, and getting manual scripts for specific components.

I am trying at the moment to have a user input component, and while my game is very small, I do like the idea of setting a script manually for how the component should react to different events (such as mouse clicks, key presses, and so on).
Right now I give the component's constructor a callback function which is later on called by the appropriate system, but this just seems hack-ish and wrong.
Basically I want to give a human player a specific script that will tell it what to do in each event, but I rather not hard-code it.

Now on the other issue - interaction between components. I like the best the idea of letting a component to send a message to all the components that its owner owns, and whoever doesn't need the event will silently ignore it (the rendering component wont try to play a sound).
While this is all nice in concept, I can't see a clean way to implement it.
At the moment, I get the owner from the entity manager, then I tell the entity manager to send the message to all the components owned by the entity, but it seems a little weird that the entity manager should be involved.
The fact that the components have their callbacks given to them as parameters at creation time is also a bit weird as stated before.

I am wondering if anyone here experienced with this type of entity systems and have better solutions then mine.

I do not care much about efficiency right now as my game is very small and hardly requires anything, so I would rather have the "purest" solution even if it's slower then more optimal ways (like keeping references in components to other components they are known to change).

Thanks in advance.
Krohm
Krohm
Basically I want to give a human player a specific script that will tell it what to do in each event, but I rather not hard-code it.
Scripting. No way around it. At best, it will be some just-connect-the-dots tool. Or perhaps you can cut corners and just give the player a choices of actions such as "cast spell X". Casting "fireball" isn't going to be different from casting "fly" hopefully.

Now on the other issue - interaction between components. I like the best the idea of letting a component to send a message to all the components that its owner owns, and whoever doesn't need the event will silently ignore it (the rendering component wont try to play a sound).
This has been discussed (although not deeply investigated) in at least two very recent threads in the software engineering forum (Demise of the game entity, Entity systems). Have you read them?
I'm currently inclined to have those components (such as sound being played, animation being looped, particle system) "just live by themselves", with the containing entity polling for updates on need for emergent behavior rather than inspection of each entity.

At the moment, I get the owner from the entity manager, then I tell the entity manager to send the message to all the components owned by the entity, but it seems a little weird that the entity manager should be involved.
The fact that the components have their callbacks given to them as parameters at creation time is also a bit weird as stated before.
Consider "Data oriented design". Long story short: the components won't exist "by themselves" (talking at a lower level here) but rather be dumb instances of data being updated by the manager in a consistent manner. Again, this is discussed in recent threads in software engineering!

I do not care much about efficiency right now as my game is very small and hardly requires anything, so I would rather have the "purest" solution even if it's slower then more optimal ways (like keeping references in components to other components they are known to change).
This has been discussed as well in a thread I've started ~10 days ago in the software engineering forum, I've found it very useful. Long story short: have an array of pointers-to-components to inspect.
Previously "Krohm"
Frank Taylor
Frank Taylor
Hi Wolfscaptain,

Cistron: an open source component-based object framework, may be of interest to you. I sorta stumbled into Entity/Component Model (Ref 1,2,3) by accident while developing my 3D GUI. In my GUI System, Widgets are containers that loosely couple input, collision, and visual components. You can combine these the components in different variations to create different types of widgets.

One day I had an epiphany and realized that the entire game world was a GUI. Why not use the event handling, messaging, and process optimizations a GUI does for other Game Entities? At that time, I thought I had come up with a completely new concept. I called it Interactive-centric design. I later discovered that the concept already had a name and was adopted by some commercial development houses as the Entity Component Model. I impressed myself with that one.
Nanoha
Nanoha

Now on the other issue - interaction between components. I like the best the idea of letting a component to send a message to all the components that its owner owns, and whoever doesn't need the event will silently ignore it (the rendering component wont try to play a sound).
While this is all nice in concept, I can't see a clean way to implement it.


This is similar to how I do mine, components send messages to the entity which owns them (I pass the owner in when I add a component). The entity can then send the message to any other components that are interested. Components have to register their interest in a message with the entity.

My physical component might send message when its position/orientation changes, the visual component can listen for those and do whatever it needs to do. I have a controlling component that sends "change direction" messages and the like which the physical component can listen for. I can have scripted components.
Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.
wolfscaptain
wolfscaptain
@ Nanoha and Techlord

Thanks for the replies, I will look into the mentioned threads and links.

@ Krohm

Yes that's the same way, except I don't like it. It ruins the "purity" of the entity system by giving components logic code rather then just data.


Over all, I really want to keep the code as "pure" as possible, meaning components are just data, systems run EVERY piece of logic, and the entity manager sort of connects everything.
On paper and words this paradigm sounds like complete paradise, just that implementing it is more trickier.
Perhaps I am just stuck in an OO mindset even when I try to get out? (what wonders me is that I never liked OO in the first place, yet I got stuck in it because of all this nonsense of it being way over rated and taught all over the internet as some godly thing ).

In the meantime while I wasn't home, I thought of moving the events to the systems (it makes a little more sense) - each system will hold a list of events, each with the owning entity and the event itself, and it will process all of them once per frame.
This sounds a little better to me, but still a little odd.

As to custom scripts - I meant, for example, two players having the same components, but reacting differently to, say, keyboard input.
This is really more for the GUI part of the code - I am not sure how much to generalize things like lists, buttons, and such.
Do they hold callbacks?
Do they just throw an ID of the element at some global event listener that will respond appropriately? (this is what I did in an old game of mine, and to be honest it was pretty neat).
Frank Taylor
Frank Taylor
Hey Wolfscaptain,

I'm developing a Entity Component System too. I really like Cistron, but, not the Boost dependency so much, so I'm writing my own. It would be interesting in comparing the our implementations. I have a few questions for the following quotes.

Yes that's the same way, except I don't like it. It ruins the "purity" of the entity system by giving components logic code rather then just data.

Over all, I really want to keep the code as "pure" as possible, meaning components are just data, systems run EVERY piece of logic, and the entity manager sort of connects everything. [/quote]

1. What is a System? Do components form Systems? I've seen components described as AI, Physics, Rendering (systems). Slightly confused.

2. Isn't the logic script itself (ASCII or Binary) Data. I store scripts as blobs of data and load them into buffers, like any other value. Executing the script is handled by the Script Component.

I do not care much about efficiency right now as my game is very small and hardly requires anything, so I would rather have the "purest" solution even if it's slower then more optimal ways (like keeping references in components to other components they are known to change).[/quote]

Perhaps I am just stuck in an OO mindset even when I try to get out? (what wonders me is that I never liked OO in the first place, yet I got stuck in it because of all this nonsense of it being way over rated and taught all over the internet as some godly thing sad.gif ).[/quote]

3. What exactly is a purest solution? I've read many different explanations on implementing Entity Components. This one made the most sense to me and helped me realize I was doing similar with my GUI. The image below provides a visual aid for the concept courtesy of Cowboy Programming:

Fig-2.gif


4. If you don't care much about efficiency right now, why repeat getting yourself stuck on a so-called purest solution (hint: OO mindset)? Just get it to work and refactor as needed. Perhaps drawing up some illustrations on how interaction between components and getting manual scripts for specific components could help in visualizing the code.
Krohm
Krohm
Yes that's the same way, except I don't like it. It ruins the "purity" of the entity system by giving components logic code rather then just data.
Over all, I really want to keep the code as "pure" as possible, meaning components are just data, systems run EVERY piece of logic, and the entity manager sort of connects everything.
Perhaps I've not explained myself well. There's nothing preventing this from happening.
For example, the statement of "components living by themselves" is intended to be read from the point of view of the code using the component. A subsystem can update it behind the scenes, sort of similar to [font="'Courier New"][color="#0000ff"]volatile[/font].
Previously "Krohm"
wolfscaptain
wolfscaptain

Hey Wolfscaptain,

I'm developing a Entity Component System too. I really like Cistron, but, not the Boost dependency so much, so I'm writing my own. It would be interesting in comparing the our implementations. I have a few questions for the following quotes.

Yes that's the same way, except I don't like it. It ruins the "purity" of the entity system by giving components logic code rather then just data.

Over all, I really want to keep the code as "pure" as possible, meaning components are just data, systems run EVERY piece of logic, and the entity manager sort of connects everything.


1. What is a System? Do components form Systems? I've seen components described as AI, Physics, Rendering (systems). Slightly confused.

2. Isn't the logic script itself (ASCII or Binary) Data. I store scripts as blobs of data and load them into buffers, like any other value. Executing the script is handled by the Script Component.

I do not care much about efficiency right now as my game is very small and hardly requires anything, so I would rather have the "purest" solution even if it's slower then more optimal ways (like keeping references in components to other components they are known to change).[/quote]

Perhaps I am just stuck in an OO mindset even when I try to get out? (what wonders me is that I never liked OO in the first place, yet I got stuck in it because of all this nonsense of it being way over rated and taught all over the internet as some godly thing sad.gif ).[/quote]

3. What exactly is a purest solution? I've read many different explanations on implementing Entity Components. This one made the most sense to me and helped me realize I was doing similar with my GUI. The image below provides a visual aid for the concept courtesy of Cowboy Programming:

[I've taken liberty to remove the gigantic image]

4. If you don't care much about efficiency right now, why repeat getting yourself stuck on a so-called purest solution (hint: OO mindset)? Just get it to work and refactor as needed. Perhaps drawing up some illustrations on how interaction between components and getting manual scripts for specific components might work could help in visualizing the code.
[/quote]


Cowboy's article is a general introduction to component oriented programming, instead of having deep inheritance hierarchies.
What I mean by entity systems (while there are a few dialects of what exactly entity systems are, I like this one the most) is going with components to the max - eliminating OOP from them completely.


This paradigm basically has three parts:
  1. Entities, which are just global unique IDs (usually implemented as integers for obvious reasons, but they can be anything that can uniquely identify each one).
  2. Components, which are chunks of data (equivalent to structures in C/C++ like languages, or classes with no methods in languages like Java that force OOP).
  3. Systems, which drive the whole program. These are normal OOP classes. Each system ideally operates on all components of its type, for example: the Render System will probably operate mainly on Render Components (of course this is just ideal, as you'd probably have some other components to take into consideration, like a Position, or Animation, or whatever).

The thing that connects all this is an Entity Manager (call it however you want, it manages entities ), which internally maps each entity to its components (how it does that is your own decision, some ways are more optimized for speed, some less).
In addition, it has methods to create entities, add/remove components to entities, get a specific component type from an entity, get all components of a specific type, and finally get all entities containing a component(s).

My issue with message passing is - who does it? the components can't do it by definition - they are just plain data, which is why it was just a quick hack.
So do the systems do it? does the entity manager do it? something else?

The same is for custom scripts per component - this can't exist by definition, so how one would make a specific entity react differently then another one given the same message?


This is all mostly theory, trying to design it in a good way to begin with rather then later on changing all the code .

I decided to stay with OOP for the game entities themselves for the time being, simply because I want to get something done already (I have only 2 entities to begin with anyway - a player and a level (which includes many tiles and 3D sprites which could be separate entities, but I coded it in such a way that they are stuck together for awesome optimizations after it lagged WebGL too much)), so these questions are more relevant for the GUI which I'll start soon.

In an old prototype, I had a GUI system which had calls that checked for events, such as a method that was called each time the mouse was clicked, giving the system the (x, y) coordinate. The system would then go over all GUI components that have the "Clickable" component and would check for collisions - if those existed, it would send a "Clicked" event with the owning entity to a global event listener.
The event listener would be queried each game loop until its queue of events finished, so the actual logic for GUI essentially lived in main.

This kept the code pretty neat in the sense that the components stayed with no logic code, and they were still separated, which is half the point of components.
I am just wondering if there's a better/neater design.

I looked at the threads in the software engineering forum, and while it's nice to see how many approaches, each with their own pros and cons there are to component oriented programming, there are, they weren't really discussing these exact two subjects (a little about sending messages).



Perhaps I've not explained myself well. There's nothing preventing this from happening.
For example, the statement of "components living by themselves" is intended to be read from the point of view of the code using the component. A subsystem can update it behind the scenes, sort of similar to [font="Courier New"][color="#0000ff"]volatile[/font].

I am sorry, I didn't really get what you mean


Whoo, I don't think I have ever written such a big wall of text in a forum. Yikes!
Frank Taylor
Frank Taylor
Thanks for the explanation Wolfscaptain.

I'm still a little foggy on your Component/System definitions, but, that's my fault. By your definition, Component appears to be a Model, or a generic "data" bucket (which is usually part of the Entity). That's throwing me off, but, I get the basics of the concept. In fact, it looks more like a software architectural pattern, than a paradigm. Can you provide an additional reference that clearly defines this as a paradigm? In many cases we intermix multiple programming paradigms to achieve goals. I use Procedural, OOP, Data-Driven, Table/Cell-Oriented, Prototype-based, Event-Driven, and Modular Programming at one point or another. Don't get caught up into the paradigm itself.

As far as Message passing goes, it appears that all three share in message passing to inter-communicate to one another.
Frank Taylor
Frank Taylor
Hi Wolfscaptain,

Started to write my own Components System. After further reading and coding, I now have a better understanding of your definitions for System/Components/Entity. In fact, I'm designing my Components to match your definitions:

  • Entities, which are just global unique IDs (usually implemented as integers for obvious reasons, but they can be anything that can uniquely identify each one).
  • Components, which are chunks of data (equivalent to structures in C/C++ like languages, or classes with no methods in languages like Java that force OOP).
  • Systems, which drive the whole program. These are normal OOP classes. Each system ideally operates on all components of its type, for example: the Render System will probably operate mainly on Render Components (of course this is just ideal, as you'd probably have some other components to take into consideration, like a Position, or Animation, or whatever).
    BTW, how is your Component Messaging coming along?

    S3GE_diag1.jpg
    Super 3D Game Platform Architecture (Full View)

    Components.png
    I'm rewriting all of my Engine Framework to use Components. Here is my current untested work in progress:


    namespace Component{

    //Component Parameter
    class Parameter{
    public:
    int Type; //{VALUE,PROPERTY,VARIABLE,SCRIPT}
    string Key;
    string Value;

    Parameter(int type, string key, string value);
    ~Parameter(void);
    };

    //Component Messaging
    class Message {

    public:
    void* Receiver;
    int Type;
    int ID; //message identifier
    int ParameterCount;
    map<int, Parameter*> ParameterMap;
    map<int, Parameter*>::iterator ParameterMapIterator;
    int State;

    Message(void);
    ~Message(void);

    static Message *Create(int type);
    static void Destroy(Message *instance);
    void Insert(int type, string key, string value);
    void Insert(Parameter &parameter);

    Message *Copy(void);

    };

    //Component Object Instance Base Class
    class Object{

    public:
    map<int, Parameter*> ParameterMap;
    map<int, Parameter*>::iterator ParameterMapIterator;
    int EntityID;
    int State;

    virtual void Start(void) =0;
    virtual void Update(void) =0;
    virtual void Stop(void) =0;
    virtual void MessageProcess(void) =0;
    };

    //Component Object Manager Base Class
    class Manager{
    public:

    string Name;
    string Description;

    //System Reference
    System* System;

    virtual list<Component::Object*> ActiveList;
    virtual list<Component::Object*>::iterator ActiveListIterator;
    virtual queue<Component::Object*> InactiveQueue;

    //Component Methods
    Object* ComponentCreate(void)=0;
    void ComponentDelete(Object* instance)=0;
    };

    //Component System Base Class
    class System{
    public:
    string Name;
    string Description;
    list<Component::Manager*> ComponentManagerList;

    //Component Manager Methods
    Component::Manager* ComponentManagerCreate(void);
    };

    namespace Entity{

    //Component Entity Instance Class Container
    class Object{
    public:

    int ID;
    int SimulationID;

    //Component Object List
    list<Component::Object*> ComponentList;

    // constructor/destructor
    Entity(int ID);
    virtual ~Entity();

    };

    //Compenent Entity Manager Class
    class Manager{
    public:

    ResourceManager *EntityResource;

    //Entity Methods
    int EntityCreate(void);
    void EntityDelete(int entityID);

    //Component Object Methods
    void ComponentAdd(Component::Object* object, list<Parameter*> parameterlist);
    void ComponentRemove(Component::Object* object);
    void ComponentRemoveAll(void);
    void ComponentUpdate(Component::Object* object);
    void ComponentUpdateAll(void);

    //Message Methods
    void MessageProcess(void); // echoes to all attached components
    };
    }
    }



    //Component Class Declarations

    class RenderSystem: public Component::System{

    class SpriteComponentManager: public Component::Manager{
    };

    class SpriteComponent: public Component::Object{
    };

    class MeshComponentManager: public Component::Manager{
    };

    class MeshComponent: public Component::Object{
    };

    class TerrainComponentManager: public Component::Manager{
    };

    class TerrainComponent: public Component::Object{
    };

    class BSPComponentManager: public Component::Manager{
    };

    class BSPComponent: public Component::Object{
    };

    };

    class AudioSystem: public Component::System{

    class MusicComponentManager: public Component::Manager{
    };

    class MusicComponent: public Component::Object{
    };

    class SoundComponentManager: public Component::Manager{
    };

    class SoundComponent: public Component::Object{
    };

    class AcousticComponentManager: public Component::Manager{
    };

    class AcousticComponent: public Component::Object{
    };

    class ParticleComponentManager: public Component::Manager{
    };

    class ParticleComponent: public Component::Object{
    };

    };

    class PlayerEntityManager: public Component::Entity::Manager{
    };

    class PlayerEntity: public Component::Entity::Object{
    );

    class BotEntityManager: public Component::Entity::Manager{
    };

    class BotEntity: public Component::Entity::Object{
    };



    //`Framework` System, Component & Entity Construction

    //Create Framework Systems
    RenderSystem *OgreRenderSystem = new RenderSystem;
    AudioSystem *MoodsterAudioSystem = new AudioSystem;

    //Create Framework Systems Component Managers
    RenderSystem::MeshComponentManager *OgreMeshComponentManager = OgreRenderSystem->ComponentManagerCreate();
    AudioSystem::MusicComponentManager *MoodsterMusicComponentManager = MoodsterAudioSystem->ComponentManagerCreate();

    //Create Game Entity Manager
    PlayerEntityManager *CombatantEntityManager = new PlayerEntityManager;

    //Create Game Entity Instance
    int TechlordID = CombatantEntityManager->EntityCreate();

    //Create Framework Component Instances
    RenderSystem::MeshComponent *OgreMeshComponent = OgreMeshComponentManager->ComponentCreate();
    AudioSystem::MusicComponent *MoodsterMusicComponent = MoodsterMusicComponentManager->ComponentCreate();

    //Add Components to Entity Instance
    CombatantEntityManager->ComponentAdd(TechlordID,OgreMeshComponent);
    CombatantEntityManager->ComponentAdd(TechlordID,MoodsterMusicComponent);

    //Modify Component Data & Logic
    OgreMeshComponent->ParameterAdd(new Parameter(0,"Name","MyCube"));
    OgreMeshComponent->Load("cube.x");

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.