Обычно это делается с помощью сообщений. Вы можете найти много деталей в других вопросах на этом сайте, как здесь или там .
Чтобы ответить на ваш конкретный пример, можно определить небольшой Message
класс, который могут обрабатывать ваши объекты, например:
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<m_components.size(); ++i)
{
// let components do some stuff with msg
m_components[i].Process(msg);
}
}
Таким образом, вы не «загрязняете» Obj
интерфейс вашего класса компонентными методами. Некоторые компоненты могут выбрать обработку сообщения, некоторые могут просто игнорировать его.
Вы можете начать с вызова этого метода непосредственно из другого объекта:
Message msg(obj1, "EmitForce(5.0,0.0,0.0)");
obj2.ProcessMessage(msg);
В этом случае obj2
s Physics
выберет сообщение и выполнит любую необходимую ему обработку. Когда это будет сделано, оно будет либо:
- Отправьте сообщение «SetPosition» себе, что
Position
выберет компонент;
- Или напрямую получить доступ к
Position
компоненту для модификаций (что совершенно неверно для дизайна, основанного исключительно Position
на Position
компонентах , поскольку нельзя предполагать, что каждый объект имеет компонент, но компонент может быть требованиемPhysics
).
Как правило, рекомендуется отложить фактическую обработку сообщения до обновления следующего компонента. Его немедленная обработка может означать отправку сообщений другим компонентам других объектов, поэтому отправка только одного сообщения может быстро привести к неразрывному стеку спагетти.
Возможно, позже вам придется перейти на более продвинутую систему: асинхронные очереди сообщений, отправка сообщений в группу объектов, регистрация / отмена регистрации для каждого компонента и т. Д.
Message
Класс может быть универсальным контейнером для простой строки , как показано выше, но обработка строк во время выполнения не очень эффективные. Вы можете использовать контейнер общих значений: строки, целые числа, числа с плавающей запятой ... С именем или, еще лучше, идентификатором, чтобы различать различные типы сообщений. Или вы также можете получить базовый класс для удовлетворения конкретных потребностей. В вашем случае вы можете представить себе, EmitForceMessage
что происходит от Message
и добавляет желаемый вектор силы, но остерегайтесь затрат времени выполнения RTTI, если вы это сделаете.