2010-07-24 20 views
6

Ich bin gerade dabei, ein Entity-Component-System zu integrieren, wie es here mit einer Physik-Engine und einer Grafik-Engine gesehen hat. Dies war alles in Ordnung, bis vor kurzem entschieden, dass die Physik in einem eigenen Thread laufen sollte. (Danke Glenn Fiedler!)Wie mache ich meine Komponente Entity System Thread sicher?

Wie es jetzt ist schließe ich einfach einen Mutex, der von allen Subsystemen geteilt wird, wenn ich auf Komponenten zugreife.

Snippet aus der Physik-Schleife:

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); 
} 

Snippet von Grafik-Schleife:

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)); 
} 

Dies ist natürlich eine sehr naive Implementierung, also versuchte ich machen die einzelnen Komponenten ihre eigenen mutexes haben. Es schien die logische Leistungswahl zu sein, aber dann wären die physikalischen Ergebnisse (wie sie durch die Positionskomponente abgefragt wurden) nicht immer konsistent und zuverlässig.

Was wäre die effizienteste Art, einen reibungslosen Aktualisierungsprozess zu erreichen? Soll ich die ganze Welt auf einmal aktualisieren lassen oder etwas inkrementeller machen?

Bearbeiten: Es ist mir aufgefallen, dass das Zeigererfassungsschema fehlerhaft ist, aber nehmen wir an, dass die Zeiger gültig sind.

Antwort

2

Wenn es um Physik-Engines geht, die in Game Engines laufen, würde ich vorschlagen, dass Sie einmal pro Frame einen Synchronisationspunkt haben, wo Sie die Positionen/welche Informationen Sie benötigen, vom Physiksystem in Ihr Komponentensystem kopieren können. Nennen Sie es Dubbel-Pufferung, wenn Sie möchten. Eine interne und externe Instanz Ihrer Position (Weltmatrix/Geschwindigkeiten usw.).

Bis zu einer Frame-Verzögerung auf Physik-Positionen ist nichts, was ein Spieler bemerken würde.

Eine andere Anmerkung, ich bevorzuge Physik-Engines in einer Weise, die so viele Threads wie möglich verwenden, während der Rest der Game-Engine vorzugsweise nichts tut. Bullet und Havok scheinen mit dieser Lösung am besten zu funktionieren.

+0

Ich sollte hinzufügen, dass Sie Ihre Physik-Engine von der Integration stoppen wollen, wenn Sie die Synchronisationspunkte machen. – Simon

+2

Ich stimme zu. Viele Synchronisationspunkte können zwar effizient aussehen, Sie müssen jedoch vor dem Zeichnen der Szene eine Barriere errichten, um den Zweck der Sperren pro Komponente zu vereiteln. Beachten Sie auch, dass Sie die Physik häufig mit einer anderen Framerate als die Grafik ausführen lassen möchten. Ich würde mich auf ein Schloss pro Physik-Update konzentrieren und die Spiel-Engine interpolieren von den neuesten Physikdaten auf jedem Grafikrahmen. –