2013-02-09 8 views
7

Ich bin definitiv etwas verloren mit der neuen C++ Chrono-Bibliothek.Behandlung einer Update-Schleife mit C++ Chrono?

Hier habe ich eine Update-Schleife. Es läuft zwei Operationen:

engine.Update() 
engine.Render() 

Dies sind lange Operationen, und es ist schwer zu sagen, wie lange sie sind.

So messen wir, wie lange sie dauerte, dann einige Berechnungen und die beste Möglichkeit, um update update Aufruf vor dem Aufruf rendern zu berechnen.

Um dies zu tun, verwende ich C++ 11 Chrono-Funktionalität. Ich wählte es, weil es wie ein guter Deal klang: Genauer, mehr Plattform abhängig. Ich stelle fest, dass ich jetzt mehr Probleme habe als jetzt.

Das Folgen ist mein Code, sowie mein Hauptproblem. Irgendeine Hilfe entweder auf dem Problem, oder ein richtiger Weg, meine Operationen zu tun, wird dringend benötigt!

Ich markierte meine Fragen in den Kommentaren direkt neben den fraglichen Zeilen, die ich unten wiederholen werde.

Die Header-Datei:

class MyClass 
{ 
private: 
    typedef std::chrono::high_resolution_clock Clock; 
    Clock::time_point mLastEndTime; 
    milliseconds mDeltaTime; 
} 

Die vereinfachte Aktualisierungsschleife

// time it took last loop 
milliseconds frameTime; 
// The highest we'll let that time go. 60 fps = 1/60, and in milliseconds, * 1000 
const milliseconds kMaxDeltatime((int)((1.0f/60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected! 
while (true) 
{ 
    // How long did the last update take? 
    frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast? 
    // Mark the last update time 
    mLastEndTime = Clock::now(); 

    // Don't update everything with the frameTime, keep it below our maximum fps. 
    while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds? 
    { 
     // Determine the minimum time. Our frametime, or the max delta time? 
     mDeltaTime = min(frameTime, kMaxDeltatime); 

     // Update our engine. 
     engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code? 

     // Subtract the delta time out of the total update time 
     frameTime -= mDeltaTime; 
    } 
    engine->Render(); 
} 

Die wichtigste Frage ist: Mein mDeltaTime kommt immer aus winzig. Es steckt im Grunde in einer fast unendlichen Schleife. Dies liegt daran, dass die kMaxDeltatime sehr klein ist, aber wenn ich 60 Frames pro Sekunde anvisiere, habe ich dann nicht die richtigen Millisekunden berechnet?

Hier sind alle Fragen von oben aufgeführt:

const milliseconds kMaxDeltatime((int)((1.0f/60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected! 

frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast? 

while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds? 

engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code? 

Es tut mir leid für die Verwirrung Jungs. Ich fühle mich wie ein Idiot mit dieser Chrono-Bibliothek. Die meisten Hilfeseiten oder Referenzmaterial oder sogar der direkte Code selbst sind sehr verwirrend zu lesen und zu verstehen, auf was ich sie anwende. Hinweise darauf, wie ich nach Lösungen oder Code suchen sollte, sind sehr willkommen!

EDIT: Joachim wies darauf hin, dass Std :: Min/Max funktioniert gut für Millisekunden! Aktualisierter Code zur Änderung.

+1

Was 'min' /' max' Funktionen für Zeiten, ist es einfach für sie einfach überladene Funktionen zu erstellen. –

+0

@JoachimPileborg Könnten Sie das näher ausführen? – MintyAnt

+0

Warum zum Teufel hast du eine "busy loop"? "Umfragen sind böse". Wenn Sie eine Verzögerung wünschen, warum nicht einen Timer blockieren? – paulsm4

Antwort

18

Wenn Sie std::chrono10 verwenden, sollten Sie so lange wie möglich Casting-Dauern vermeiden oder Dauern in rohe Integralwerte umwandeln. Stattdessen sollten Sie sich an die natürlichen Laufzeiten halten und die Typensicherheit ausnutzen, die Durationstypen bieten.

Im Folgenden finden Sie eine Reihe spezifischer Empfehlungen. Für jede Empfehlung ziehe ich Zeilen Ihres ursprünglichen Codes und zeige dann, wie ich diese Zeilen umschreiben würde.


const milliseconds kMaxDeltatime((int)((1.0f/60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected! 

gibt es keinen Grund, diese Art der Berechnung zu tun Konstanten mit manueller Konvertierung.Stattdessen können Sie tun:

typedef duration<long,std::ratio<1,60>> sixtieths_of_a_sec; 
constexpr auto kMaxDeltatime = sixtieths_of_a_sec{1}; 

frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast? 

Sie können nur den Wert in seiner nativen Typ halten:

auto newEndTime = Clock::now(); 
auto frameTime = newEndTime - mLastEndTime; 
mLastEndTime = newEndTime; 

while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds? 

Stattdessen verwenden:

while (frameTime > milliseconds(0)) 

engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code? 

Am besten ist es, Code zu schreiben, die chrono::duration Typen im gesamten verwendet, und nicht an allen generischen integralen Typen zu verwenden, aber wenn Sie wirklich brauchen Um einen generischen Integraltyp zu erhalten (zum Beispiel, wenn Sie eine long an eine API eines Drittanbieters weitergeben müssen), können Sie Folgendes tun:

auto mDeltaTime = ... // some duration type 

long milliseconds = std::chrono::duration_cast<std::duration<long,std::milli>>(mDeltaTime).count(); 
third_party_api(milliseconds); 

Und das Delta bekommen Sie so etwas wie tun sollen:

typedef std::common_type<decltype(frameTime),decltype(kMaxDeltatime)>::type common_duration; 
auto mDeltaTime = std::min<common_duration>(frameTime, kMaxDeltatime); 
+4

+1 Sehr schön erklärt. –

+0

Ich weiß, das ist schon lange vorbei, aber der Aufruf std :: common_type kompiliert nicht für mich mit clang ++ auf linux. Es heißt "kein Mitglied angerufen" Typ "existiert", was dazu führt, dass der min-Aufruf auch nicht kompiliert wird. – Joe

+0

Es hatte mit der Initialisierungsliste zu tun Ich denke, den Compiler zu vermasseln. – Joe