Jump to content
  • Advertisement
Sign in to follow this  
l0k0

Component Entity Model Message Passing in C++

This topic is 2521 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm implementing the generic string based message passing functionality seen in other component entity models. My idea is to do the following: keep a hash table in each component of string names and member function addresses. When sending a message from a game object, it looks for a function with the given name in each component/behavoir. If found it is called and the args are passed to it.

Here are my concerns with this approach:
1) My current idea is to pass a void ** array as the arguments so the function prototypes are consistent. I don't think the template ju jitsu would be worth it here, if even doable for "all" or "most" function prototypes.
2) How might you handle returns from sendMessage complicit functions? Put them at the end of the array? This doesn't seem very intuitive but is there another option?
3) Right now if two components have the same string name message handler, when sendMessage is invoked, only one of them will be called. This is a bit concerning. Anyway to get around this besides using descriptive names. Consider this example:


class Armor : public Component {

DECLARE_COMPONENT(Armor, ARMOR_ID, Component)
public:
void setHealth(void **args) {
// set the armor health
}

Armor() : Component() {
REGISTER_FUNC(Armor, "setHealth", &setHealth);
}

};

class Health: public Component {

DECLARE_COMPONENT(Health, HEALTH_ID, Component)
public:
void setHealth(void **args) {
// set the health
}

Health() : Component() {
REGISTER_FUNC(Health, "setHealth", &setHealth);
}

};




GameObject.sendMessage() will only call one. broadcastMessage() will call both despite this being undesirable. Is the only way to avoid this to use more descriptive message names, e.g. "Health_SetHealth" and "Armor_SetArmor". I realize that in some cases this is prefferred. For example, one component can be aware of a "health changed" event without any dependencies on the actual health component. For things like A.I. scripts this can keep things decoupled and encapsulated.

Also, I'm aware that member function pointers are a PITA when inheritance is concerned. My DECLARE macro already handles this somewhat messy process by generating a unique typedef and table name from the classname and calling the base class's implementation of handleMessage if nothing is found. I'm more interested with alternatives/solutions to the ambiguous name issue and the rather clunky practice of passing void pointer arrays for everything.

Thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement

I'm implementing the generic string based message passing functionality seen in other component entity models.

This kind of generic string-based message passing is too slow, too fragile, and doesn't offer enough benefit to be worthwhile. You are implementing a component system here, not a scripting language (and if you need one of those, it should probably operate on a higher level of abstraction).

My idea is to do the following: keep a hash table in each component of string names and member function addresses. When sending a message from a game object, it looks for a function with the given name in each component/behavoir. If found it is called and the args are passed to it.[/quote]
Why do you need this to be handled with strings? You already know the function name and the target entity, so call it directly (this is what abstract interfaces and/or boost::function were invented for in the first place).

1) My current idea is to pass a void ** array as the arguments so the function prototypes are consistent. I don't think the template ju jitsu would be worth it here, if even doable for "all" or "most" function prototypes.[/quote]
So you are going to throw out every bit of type safety? Might as well write this in a duck-typed language then (Python works well).

2) How might you handle returns from sendMessage complicit functions? Put them at the end of the array? This doesn't seem very intuitive but is there another option?[/quote]
Again, type safety is your friend - don't kill it for no reason. If you can't just call the function directly (via an abstract interface pointer), then figure out how to use boost::function and/or boost::signals to pass messages in a type safe fashion.

3) Right now if two components have the same string name message handler, when sendMessage is invoked, only one of them will be called.[/quote]
That's true of any programming language. Use a naming system that avoids this type of ambiguity (why exactly does 'Amour' have 'Health'? It would be clearer to name it 'strength' or 'durability').

Share this post


Link to post
Share on other sites
1) I'd just use a void*, and each message can cast it to a struct -- e.g. [font=courier new,courier,monospace]void SetHealth(void* a) { health_msg* arg = (health_msg*)a; ... }[/font]
2) If the caller wants an output value, then have [font=courier new,courier,monospace]SetHealth[/font] write into a member of the [font=courier new,courier,monospace]health_msg[/font] structure.
3) ...What you're describing with this system is a (verbose way of making a) programming language that lets you write this code:struct Armor { void setHealth(int h); };
struct Health { void setHealth(int h); };
struct Player { private: Armor a; Health h; }

Player p;
p.setHealth(42);//automagically calls p.a.SetHealth OR p.h.SetHealth (undefined which)
p.setHealth<Broadcast>(42);//automagically calls p.a.SetHealth AND p.h.SetHealth
My question is - why do you want to program this way at all? This message based idiom just seems like a bad way to architect anything.

What's wrong with hooking up events in a way that you know exactly what's going on and don't have to worry about things breaking?struct Player
{
Player()
{
h.healthChangedEvent.Add( new EventListener(&a, a::OnHealthChanged) );
}
private:
Health h; Armor a;
};

Share this post


Link to post
Share on other sites

This topic is 2521 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!