I'm not sure how exactly objects do things to other objects in a component based design.
Say I have an Obj
class. I do:
Obj obj;
obj.add(new Position());
obj.add(new Physics());
How could I then have another object not only move the ball but have those physics applied. I'm not looking for implementation details but rather abstractly how objects communicate. In an entity based design, you might just have:
obj1.emitForceOn(obj2,5.0,0.0,0.0);
Any article or explanation to get a better grasp on a component driven design and how to do basic things would be really helpful.
Answer
That is usually done using messages. You can find lots of details in other questions on this site, like here or there.
To answer your specific example, a way to go is to define a small Message
class that your objects can process, e.g:
struct Message
{
Message(const Objt& sender, const std::string& msg)
: m_sender(&sender)
, m_msg(msg) {}
const Obj* m_sender;
std::string m_msg;
};
void Obj::Process(const Message& msg)
{
for (int i=0; i {
// let components do some stuff with msg
m_components[i].Process(msg);
}
}
This way you're not "polluting" you Obj
class interface with component-related methods. Some components can choose to process the message, some might just ignore it.
You can start by calling this method directly from another object:
Message msg(obj1, "EmitForce(5.0,0.0,0.0)");
obj2.ProcessMessage(msg);
In this case, obj2
's Physics
will pick the message, and do whatever processing it needs to do. When done, it will either:
- Send a "SetPosition" message to self, that the
Position
component will pick; - Or directly access the
Position
component for modifications (quite wrong for a pure component-based design, as you can't assume every object has aPosition
component, but thePosition
component could be a requirement ofPhysics
).
It's generally a good idea to delay the actual processing of the message to the next component's update. Processing it immediately could mean sending messages to other components of other objects, so sending just one message could quickly mean an inextricable spaghetti stack.
You'll probably have to go for a more advanced system later on on: asynchronous message queues, sending messages to group of objects, per-component registering/unregistering from messages etc.
The Message
class can be a generic container for a simple string as shown above, but processing strings at runtime isn't really efficient. You can go for a container of generic values: strings, integers, floats... With a name or better yet, an ID, to distinguish different types of messages. Or you can also derive a base class to fit specific needs. In your case, you could imagine an EmitForceMessage
that derives from Message
and adds the desired force vector -but beware of the runtime cost of RTTI if you do so.
No comments:
Post a Comment