Entity Component System: Messaging with CRTP

Published January 31, 2015
Advertisement
So after a long while fighting with templates I have finally got a decent implementation of the ECS. I now have Systems, Components and Component Pools.

There is a Component Pool for each component and that holds every single component of that type.

Each System keeps track of each of the entities that is registered for it and then on update the system loops through all the entities getting the components that it needs for that entity and performing the actions on it.

This new way of doing things, having systems work on their own will give me the opportunity to add thread pools once that is necessary. This will allow me to use worker threads for sections of entities registered for the system.

So that is the general usage of the Systems and Components. The next part I will talk about is messaging, this has been a very tricky part of the Entity System.

I have again used CRTP to accomplish this, and I believe allowing a system to register for messages is easier than ever now.

The Messaging system is technically something completely seperate from the Entity System/Component architecture and because of this it is not just Systems that can listen for messages.

Okay so how does it work?

So the Message class is where the CRTP occurs, each derived message type will supply itself as the template parameter for the base class:class DerivedMessage : public Message{public: DerivedMessage(); virtual ~DerivedMessage(){};protected: };
This allows for much easier dispatch of the messages now to show how to make a class receive messages:

first of all you have to derive the class that will listen to the messages from the MessageListener class supplying the message you will be using:template < class MessageType >class MessageListener{public: virtual void HandleMessage(MessageType* message) = 0;};class MovementSystem : public System, public MessageListener, public MessageListener{public: MovementSystem(MessageManager* msgManager); virtual void Update(); virtual ~MovementSystem(void); void HandleMessage(MovementMessage* message); void HandleMessage(RotationMessage* message); virtual void RegisterMessages();};
The next step is merely to register to receive the messages of a certain type in the RegisterMessages function. This is called just after creation of any System.void MovementSystem::RegisterMessages(){ mMessageManager->RegisterListener(this); mMessageManager->RegisterListener(this);}
and then of course all that is left is to handle the messages with each of the HandleMessage functions.

Finally this is a little demo program that shows the use of the ECS and messaging:int _tmain(int argc, _TCHAR* argv[]){ MessageManager messManager; EntityManager manager(&messManager); Entity* newEnt = manager.CreateEntity( string( "MyFirstEntity" ) ); newEnt->AddComponent( newEnt ); newEnt->AddComponent( newEnt ); newEnt->AddSystem(); messManager.SendMessage( 40.0f, 0.2f, 0.0f ); messManager.SendMessage( 20.0f, 0.0f, 0.0f ); return 0;}
I have used variadic templates throughout to make creating Messages and Components really simple.

So I believe this is a fairly flexible approach, there are probably a few more things that I could do to make this better but for now I am going to leave it as it is and try and re-implement all the functionality that is in my previous version of the ECS. Once this is all integrated back into my Engine then I will run some tests and see if there is need for any more changes.

All is going well after a lot of frustrating times with templates. There are still some things that need tidying up to ensure the system is a little more robust but I am very happy with the progress.

Thanks smile.png
2 likes 5 comments

Comments

Aardvajk
Interesting stuff, thanks for sharing. I was researching CRTP earlier today funnily enough but what you have posted has helped clarify a few things for me. I'm wondering if I can use this in my signals and slots system to move some of the decision making to compile time. Your message stuff has given me some ideas to try out.
January 31, 2015 05:32 PM
Juliean

Your approach, es well as your whole system, seems to be pretty similar to how I am approaching ECS, so you seem to be on a good way. I actually really like your idea about inheriting from a MessageListener<> for the different supported messages types, and will probaby adopt something along those lines. Thanks for the inspiration, and keep up the good work!

January 31, 2015 05:44 PM
JordanBonser

Thanks Aardvajk, this is the first time I've tried implemeting CRTP and it is definitely really powerful. I'm glad I've given someone inspiration to try something new :)

Juliean this is actually really strange, I've been using your blog posts along with EntityX as reference for all the work I've been doing. In fact the whole messaging system I only tried after you mentioned that you would like to make yours work that way. So thank you for the inspiration to try it :)

January 31, 2015 08:00 PM
Juliean

Cool, good to know my journal is actually helping people. And seeing that I can now also profit from it, makes it even better. I quess what goes around really comes around, sometimes ;)

February 01, 2015 07:37 PM
BeerNutts

The messaging looks like what entityX has been doing. I suppose there's only so many ways of making a messaging system.

In fact, if you haven't yet, take a look at his ECS implementation entityx, it sounds a lot like yours.

Good luck.

EDIT: Oops, I just saw you've already been looking at entityx, so disregard!

February 02, 2015 09:50 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement