I've done my research and read as many articles and posts on messaging and ECS's as I could find to help me get mine working. However, I'm at a roadblock on how to get my messag functionality to be handled correctly.
A little information on my ECS system.
Pieces:
Entities - Generic objects that only contains a list of attached components, has a few methods to ask if it has certain components and to retrieve them.
Components - Only holds data specific to their nature and all have a bitMask denoting the component type.
Systems - Functionality code specific to their nature and keeps a list of components it will process.
Messages - Messages are currently created via the MessageInfo class. A message can be created easily using this line of code:
MessageInfo* msg = new MessageInfo(MESSAGE_TYPE, LISTENER_ENTITY, boost::ANY PARAMS);
I am trying to keep things decoupled as possible and have thought about adding a static MessageCenter that I can push messages to which will then either dispatch them immediately or throw them into a queue (depending on the push function call).
Example being that a message is created and pushed to the message center. The message center then immediately looks through its map of systems that care about X message and dispatches the message to a "RecieveMessage" method that's inherent to all systems. This approach sounded really good to me, so I started to develop it on paper and ended up running into a wall.
Let me put forth one of the scenario's I ran up against.
Scenario:
I have a text label entity being used as a % indicator with the position (x/y coords) component and text component (string, font size, etc). I want to alter some data properties of this entity, such as the text displayed and its color.
Since I know that all systems have a recieveMessage method I am quickly able to encapsulate functionality specific to those types of requests as shown below.
void SOMESYSTEM::RecieveMessage(MessageInfo* messageInfo)
{
switch(messageInfo->GetMessageType())
{
case MessageType::CHANGE_TEXT:
{
boost::any params = messageInfo->GetParams();
if(params.type() == typeid(std::tuple<BaseComponent*,std::string>))
{
auto param = boost::any_cast<std::tuple<BaseComponent*,std::string>>(params);
TextComponent* textComponent = static_cast<TextComponent*>(std::get<0>(param));
textComponent->SetTextString(std::get<1>(param));
}
}break;
case MessageType::CHANGE_TEXT_COLOR:
{
boost::any params = messageInfo->GetParams();
if(params.type() == typeid(std::tuple<BaseComponent*,sf::Color>))
{
auto param = boost::any_cast<std::tuple<BaseComponent*,sf::Color>>(params);
TextComponent* textComponent = static_cast<TextComponent*>(std::get<0>(param));
textComponent->SetCurrentColor(std::get<1>(param));
}
}break;
}
}
The wall I run into is where do I put this functionality? Currently the only system that touches text components is my RenderTextSystem. It wouldn't seem proper to implement that RecieveMessage function wanting those specific messages. That system just draws the text to the screen. I could be over-engineering here though.
I have other scenarios similar to this and figured if I could solve this one, I could end up solving 99% of the others.