2013-02-09 19 views
7

Sono decisamente un po 'perso con la nuova libreria di crono C++.Gestione di un ciclo di aggiornamento utilizzando C++ Chrono?

Qui ho un ciclo di aggiornamento. Esegue due operazioni:

engine.Update() 
engine.Render() 

Queste sono operazioni lunghe, ed è difficile dire quanto tempo sono.

Quindi, misuriamo quanto tempo hanno impiegato, quindi facciamo alcuni calcoli e calcoliamo il modo migliore per chiamare gradualmente l'aggiornamento prima di chiamare il rendering.

Per fare ciò, sto utilizzando la funzionalità Chrono di C++ 11. L'ho scelto perché sembrava un buon affare: più preciso, più dipendente dalla piattaforma. Sto scoprendo che sto colpendo più problemi di adesso, però.

Di seguito è riportato il mio codice, nonché il mio problema principale. Qualsiasi aiuto su entrambi i problemi, o un modo corretto per fare le mie operazioni, è molto necessario!

Ho contrassegnato le mie domande nei commenti direttamente accanto alle righe in questione, che verranno ripetute di seguito.

Il file di intestazione:

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

L'aggiornamento semplificato ciclo

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

La domanda principale è: mio mDeltaTime viene sempre fuori molto piccolo. È praticamente bloccato in un loop quasi infinito. Questo perché kMaxDeltatime è molto piccolo, ma se ho come target 60 frame al secondo, non ho calcolato i millisecondi corretti?

Ecco tutte le domande elencate dall'alto:

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? 

Mi dispiace per i ragazzi confusione. Mi sento un idiota con questa libreria chrono. La maggior parte dei siti di aiuto, o materiale di riferimento, o anche il codice diretto stesso è molto confuso per leggere e capire a cosa sto applicando. Indicatori su come dovrei cercare soluzioni o codici sono molto graditi!

MODIFICA: Joachim ha sottolineato che std :: min/max funziona bene per millisecondi! Codice aggiornato per riflettere il cambiamento.

+1

Per quanto riguarda 'min' /' funzioni max' per i tempi, è facile creare semplici funzioni sovraccaricate per loro. –

+0

@JoachimPileborg Potresti elaborare? – MintyAnt

+0

Perché diamine hai un "loop occupato"? "Polling is evil". Se vuoi un ritardo, perché non bloccare un timer? – paulsm4

risposta

18

Quando si utilizza std::chrono, è necessario evitare, per quanto possibile, la durata delle conversioni o la conversione delle durate in valori interi grezzi. Invece dovresti attenersi alle durate naturali e approfittare del tipo di sicurezza che i tipi di durata forniscono.

Di seguito è riportata una serie di raccomandazioni specifiche. Per ogni raccomandazione citerò le righe del tuo codice originale e poi mostrerò come scriverò di nuovo quelle righe.


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! 

Non c'è alcun motivo per fare questo tipo di calcolo con costanti conversione manuale.Invece si può fare:

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? 

Si può solo mantenere il valore nel suo tipo nativo:

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? 

usare al posto:

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? 

E 'meglio scrivere codice che utilizza chrono::duration tipi in tutto, piuttosto che usare tipi integrali generici a tutti, ma se si ha realmente bisogno per ottenere un tipo integrale generico (ad esempio se devi passare un long a un'API di terze parti), puoi fare qualcosa del tipo:

auto mDeltaTime = ... // some duration type 

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

E per ottenere il delta si dovrebbe fare qualcosa di simile:

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

+1 Molto ben spiegato. –

+0

So che è passato molto tempo, ma la chiamata std :: common_type non viene compilata per me con clang ++ su linux. Dice "nessun membro chiamato" tipo "esiste" che fa sì che anche la chiamata minima non venga compilata. – Joe

+0

Ha avuto a che fare con l'elenco di inizializzazione che penso avvitare il compilatore. – Joe