Обычно это делается с помощью сообщений. Вы можете найти много деталей в других вопросах на этом сайте, как здесь или там .
Чтобы ответить на ваш конкретный пример, можно определить небольшой 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);
В этом случае obj2s Physicsвыберет сообщение и выполнит любую необходимую ему обработку. Когда это будет сделано, оно будет либо:
- Отправьте сообщение «SetPosition» себе, что
Position выберет компонент;
- Или напрямую получить доступ к
Positionкомпоненту для модификаций (что совершенно неверно для дизайна, основанного исключительно Positionна Positionкомпонентах , поскольку нельзя предполагать, что каждый объект имеет компонент, но компонент может быть требованиемPhysics ).
Как правило, рекомендуется отложить фактическую обработку сообщения до обновления следующего компонента. Его немедленная обработка может означать отправку сообщений другим компонентам других объектов, поэтому отправка только одного сообщения может быстро привести к неразрывному стеку спагетти.
Возможно, позже вам придется перейти на более продвинутую систему: асинхронные очереди сообщений, отправка сообщений в группу объектов, регистрация / отмена регистрации для каждого компонента и т. Д.
MessageКласс может быть универсальным контейнером для простой строки , как показано выше, но обработка строк во время выполнения не очень эффективные. Вы можете использовать контейнер общих значений: строки, целые числа, числа с плавающей запятой ... С именем или, еще лучше, идентификатором, чтобы различать различные типы сообщений. Или вы также можете получить базовый класс для удовлетворения конкретных потребностей. В вашем случае вы можете представить себе, EmitForceMessageчто происходит от Messageи добавляет желаемый вектор силы, но остерегайтесь затрат времени выполнения RTTI, если вы это сделаете.