Answers:
通常使用消息来完成。您可以在此站点上的其他问题中找到很多详细信息,例如此处或此处。
为了回答您的特定示例,一种方法是定义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
的Physics
会挑消息,做任何处理,它需要做的。完成后,它将:
Position
组件将选择该消息;Position
组件以进行修改(对于纯基于组件的设计来说,这是非常错误的,因为您不能假定每个对象都有一个Position
组件,但是该Position
组件可能是的要求Physics
)。将消息的实际处理延迟到下一个组件的更新通常是一个好主意。立即处理该消息可能意味着将消息发送到其他对象的其他组件,因此仅发送一条消息可能会很快意味着一个不可分割的意大利面条堆栈。
稍后可能需要使用更高级的系统:异步消息队列,将消息发送到对象组,按组件注册/从消息中注销等。
的Message
类可以是一个通用的容器,用于一个简单的字符串如上述所示,但在运行时处理的字符串是没有真正有效的。您可以使用一个通用值的容器:字符串,整数,浮点数...使用名称或更佳的ID来区分不同类型的消息。或者,您也可以派生基类以满足特定需求。在您的情况下,您可以想象一个EmitForceMessage
从Message
所需力矢量派生并添加所需力矢量的,但要小心RTTI的运行时成本。
dynamic_cast
可能成为瓶颈,但是我现在暂时不必担心。如果仍然有问题,您仍然可以稍后对其进行优化。基于CRC的类标识符的工作原理像一个超级按钮。
为了解决与您显示的问题类似的问题,我要做的是添加一些特定的组件处理程序并添加某种事件解析系统。
因此,对于您的“ Physics”对象,在初始化该对象时会将其自身添加到Physics objetcs的中央管理器中。在游戏循环中,此类管理器具有自己的更新步骤,因此,在更新此PhysicsManager时,它将计算所有物理相互作用,并将它们添加到事件队列中。
产生所有事件之后,您可以解决事件队列,只需检查发生了什么并相应地采取措施,就您的情况而言,应该有一个事件表明对象A和B以某种方式发生了交互,因此您可以调用generateForceOn方法。
这种方法的优点:
缺点:
我希望这有帮助。
PS:如果有人有更清洁/更好的方法来解决此问题,我真的很想听听。
obj->Message( "Physics.EmitForce 0.0 1.1 2.2" );
// and some variations such as...
obj->Message( "Physics.EmitForce", "0.0 1.1 2.2" );
obj->Message( "Physics", "EmitForce", "0.0 1.1 2.2" );
关于此设计的一些注意事项: