如何使组件实体系统线程安全?

nil*_*urt 6 c++ multithreading components boost entity-framework

我目前整合的实体组件系统,如看到这里,与物理引擎和图形引擎.这一切都很好,直到最近决定物理应该在自己的线程中运行.(感谢Glenn Fiedler!)

就像现在一样,我只是在访问组件时锁定所有子系统共享的互斥锁.

来自物理循环的片段:

lock_guard<mutex> lock( m_EntMutex );
entitymap::iterator it;
for ( it = m_Ents.begin(); it != m_Ents.end(); ++it )
{
    // Get physics component from entity
    // This is guaranteed to work ( component must exist for it to present in the map )
    shared_ptr<comp_phys> phys( static_cast<comp_phys*>( it->second->getComponent( COMP_PHYS ).lock().get() ) );
    // Get resulting Box2D vector
    b2Vec2 vec = phys->getBody()->GetPosition();

    // Get position component from entity
    // Same as above, but this is the component shared with the graphics subsystem   
    shared_ptr<comp_pos> pos( static_cast<comp_pos*>( it->second->getComponent( COMP_POS ).lock().get() ) );
    // Update position component from Box2D vector
    pos->setPosition( vec.x, vec.y, 0 );
}
Run Code Online (Sandbox Code Playgroud)

来自图形循环的片段:

lock_guard<mutex> lock( m_EntMutex );
entitymap::iterator it;
for ( it = m_Ents.begin(); it != m_Ents.end(); ++it )
{
    // Get position component from entity
    // This is shared with the physics subsystem
    shared_ptr<comp_pos> pos( static_cast<comp_pos*>( it->second->getComponent( COMP_POS ).lock().get() ) );
    // Get position from position component
    doubleVec3 vec = p->getPosition();

    // Get graphics component from entity
    shared_ptr<comp_gfx> gfx( static_cast<comp_gfx*>( it->second->getComponent( COMP_GFX ).lock().get() ) );
    // Update graphics component from position component
    gfx->getObject()->getParentSceneNode()->setPosition( float(vec.x), float(vec.y), float(vec.z) );
} 
Run Code Online (Sandbox Code Playgroud)

这显然是一个非常天真的实现,所以我尝试使各个组件都有自己的互斥体.这似乎是合乎逻辑的性能选择,但物理结果(通过位置组件查询)并不总是一致和可靠的.

什么是实现平滑更新过程的最有效方式?我应该让它一次更新整个世界还是做一些更多的增量?

编辑:我注意到指针获取方案存在缺陷,但让我们假设指针有效.

Sim*_*mon 2

当涉及到在游戏引擎中运行的物理引擎时,我建议您每帧都有一个同步点,您可以在其中将物理系统中可能需要的位置/任何信息复制到组件系统中。如果您愿意,可以将其称为双缓冲。您位置的内部和外部实例(世界矩阵/速度等)。

任何游戏玩家都不会注意到物理位置上最多一帧的延迟。

另一方面,我更喜欢以使用尽可能多的线程的方式实现物理引擎,而游戏引擎的其余部分最好什么都不做。Bullet 和 Havok 似乎最适合此解决方案。

  • 我同意。拥有许多同步点可能看起来很高效,但您仍然需要在绘制场景之前设置障碍,从而违背了每个组件锁的目的。另请注意,您通常希望让物理以与图形不同的帧速率运行。我会专注于每次物理更新一个锁,并让游戏引擎根据每个图形帧上的最新物理数据进行插值。 (2认同)