8
\$\begingroup\$

I'm trying to implement a component-based entity system but am a bit confused on how I should handle the messaging. There are two problems I'd like to resolve so I can test the system. Below is the code I have so far,

The Entity class:

class Entity{
public:
    Entity(unsigned int id):
    id_(id)
    {};
    void handleMessage(BaseMessage &message){
        for(auto element: components_){
            element.second->handleMessage(message);
        }
    }
    template<class T>
    void attachComponent(T *component){
        //Consider making safer in case someone tries to attach same component type twice
        components_[typeid(T).hash_code()] = component;
    }
    template<class T>
    void detachComponent(void){
        components_.erase(typeid(T).hash_code());
    }
    template<class T>
    T* getComponent(void)const{
        return *components_.find(typeid(T).hash_code());
    }
    unsigned int getInstanceID(void)const{
        return id_;
    }
private:
    unsigned int id_;
    std::map<size_t, BaseComponent*> components_;
};

The Base Component and Message classes:

class BaseComponent{
public:
    virtual void handleMessage(BaseMessage &message){};
};

class BaseMessage{
public:
    virtual int getType(void) = 0;
};

1. Message Type Handling

My first question is how I should handle the different (derived from BaseMessage) message types.

I have thought of two ways for handling the message types of the derived message types. One is to generate a hash (i.e. using FNV) from a string that names the message type and use that hash to determine the message type. So the handleMessage(BaseMessage &message) function, would first extract this hash from the message and then do a static_cast to the appropriate type.

The second method is to use a template as follows (similar to the attachComponent methods of the entity class),

template<class T>
handleMessage(T& message){};

and make specializations for each message type the specific component is going to make.

Are there any drawbacks using the second method? What about performance-wise, why don't I see this kind of use more often?

2. Input Handling

My second question is what would be the optimal (in terms of latency and ease of use) way to handle input?

My thought was to create an InputHandlerComponent which registers with the keyboard class to listen to specific key presses defined possibly in some file. For example

keyboard.register( player.getComponent<InputHandler>() , 'W')

I wish there was a more concise guide to component based systems but I guess there are many different ways to do the same things. I have more questions but I think it'd be wiser to first try implementing what I can.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

In a typical entity system you leave systems to have all the logic for your game and components to store data only, and your entities are just a simple identifier. Input handling would be much easier that way and not to mention the flexibility of your game.

There are plenty of ways to handle events, such as: the observer pattern, or signals/slots. You could do message handling with templates/virtual functions or function pointers, however it'd probably be easier to use boost::signals, even known it's not that great for performance. If you want performance*, I suggest you use templates and virtual functions or function pointers.

*I noticed that your code could really be optimised. There are alternatives to the typeid operator, which are actually faster than using typeid. Such as using templates/macros and simple integers to define a class's ID.

You can look at my Entity System if you need some inspiration (which is inspired from the Java framework Artemis). Although I haven't implemented a way to handle events (other than entity-related events), I left that up to the user, but after sussing out the entityx library, which I found on reddit. I figured I might be able to add an event system to my library. Please do note that my entity system isn't 100% complete on what features I want, but it works and has decent performance (but I could optimize, especially with the way I'm storing entities).

Here's what you could possibly do to handle events (inspired from entityx):

BaseReceiver/BaseListener

  • A base class so you may store listeners/receivers.

Receiver/Listener

  • This is a template class and requires you to override the virtual function recieve(const T&), where T is event information.
  • Classes that want to be notified by events that send specific information when an event occurs must inherit from this class.

EventHandler

  • Emits/fires events
  • Has a list of Receivers/Listeners objects that will be notified by fired events

I've implement this design in C++, just now, without the use of boost::signals. You can see it here.

Pros

  • Statically typed
  • Virtual functions (faster than boost::signals, well it should be)
  • Compile-time errors if you didn't emit notifications correctly
  • C++98 compatible (I believe)

Cons

  • Requires you to define functors (you can't handle events in a global function)
  • No event queue; just register & fire away. (which may be not what you want)
  • Not direct calls (shouldn't be that bad for events)
  • No multiple event handling on the same class (this could be modified so it does allow multiple events, via multiple inheritance, but may take some time to implement)

Also, I have an example in my entity system, which does deal with rendering and input handling, it's quite simple but it presents many concepts to understand my library.

\$\endgroup\$
6
  • \$\begingroup\$ Can you give an example of a faster way to discover types without typeid? \$\endgroup\$
    – Luke B.
    Commented Jan 16, 2013 at 13:32
  • \$\begingroup\$ "In a typical entity system you leave systems to have all the logic for your game and components to store data only" - there is no such thing as a 'typical' entity system. \$\endgroup\$
    – Den
    Commented Jan 16, 2013 at 22:28
  • \$\begingroup\$ @LukeB. Look at my entity system's source code, I don't use typeid (look at Component and ComponentContainer). Basically, I store the "type" of a component as an integer, I have a global integer that I increment per type of component. And I store components in a 2d array, where the first index is the entity's ID and the 2nd index is the the component type's ID, i.e. components[entityId][componentTypeId] \$\endgroup\$ Commented Jan 17, 2013 at 0:53
  • \$\begingroup\$ @miguel.martin. Thank you for your answer. I think my confusion comes mostly from the fact there are several ways to implement the entity system and to me all have their drawbacks and benefits. For example, in the approach you use, you have to register new component types using CRTP, which I personally dislike since this requirement is not explicit. I think I'll have to reconsider my implementation. \$\endgroup\$ Commented Jan 17, 2013 at 3:49
  • 1
    \$\begingroup\$ @MarsonMao fixed \$\endgroup\$ Commented Aug 18, 2015 at 10:18
1
\$\begingroup\$

I'm working on a component-based entity system in C#, but the general ideas and patterns still apply.

The way I handle message types is that each component subclass calls Component's protected RequestMessage<T>(Action<T> action) where T : IMessage method. In English, that means that the component subclass requests a specific type of message and provides a method to be called when the component receives a message of that type.

That method gets stored and when the component receives a message, it uses reflection to get the message's type, which is then used to look up the associated method and invoke it.

You can replace the reflection with whatever other system you want, hashes are your best bet. Look into multiple dispatch and visitor pattern for some other ideas though.

As for input, I chose to do something entirely different that what you're thinking. An input handler will separately convert keyboard/mouse/gamepad input into a flags enumeration (bitfield) of possible actions (MoveForward, MoveBackwards, StrafeLeft, Use, etc.) based on user settings/what the player has plugged into the computer. Each component gets a UserInputMessage every frame that contains both the bitfield and the player's look axis as a 3d vector (gearing development towards a first person shooter). This also makes it easy to let players change their key bindings.

Like you said at the end of your question, there are many different ways of creating a component-based entity system. I've geared my system heavily towards the game I'm making, so naturally some of the things I do may not make any sense in the context of, say, an RTS, but it's still something that's been implemented and that's been working for me so far.

\$\endgroup\$

You must log in to answer this question.

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