Voglio che succeda qualcosa ogni N secondi, come lo farei? Magari usa un timer ma come?
Voglio che succeda qualcosa ogni N secondi, come lo farei? Magari usa un timer ma come?
Risposte:
Un approccio comune è quello di utilizzare il ciclo di aggiornamento e il delta time.
float timerCurrent = 0f;
float timerTotal = 5f;
Update() {
timerCurrent += deltaTime;
if(timerCurrent >= timerTotal) {
//do timer action
timerCurrent -= timerTotal;
}
}
Ciò suppone che tu abbia accesso a una deltaTime
variabile. Il tempo delta è semplicemente il tempo trascorso dall'ultimo fotogramma. Molti motori avranno questo a tua disposizione, oppure puoi saperne di più sulla configurazione del tuo qui .
Nella maggior parte delle lingue, è necessario avviare l'orologio con una sorta di chiamata di funzione lungo le linee di clock.startTimer()
prima di entrare nel loop principale. Quindi, è necessario memorizzare il valore dell'ora prima di inserire il ciclo principale in una variabile con una funzione simile time = clock.getTime()
. Memorizza il tuo tempo di passaggio in variabile n
.
Nel tuo ciclo principale, il segno di spunta che vuoi fare è qualcosa di simile
if(time + n <= clock.getTime())
//do stuff
time = clock.getTime() //important to assign new time value here
Nota: non sono sicuro di quale lingua / libreria tu stia guardando, quindi questo è solo un algoritmo generico che mi è venuto in mente. Potrebbe non soddisfare esattamente le tue esigenze. Alcune lingue / librerie richiedono la creazione di un oggetto orologio mentre altre possono semplicemente effettuare direttamente una chiamata di funzione.
In base ai commenti seguenti, è necessario prestare attenzione ai problemi di threading in base alla lingua utilizzata. Dovresti anche usare un doppio float per memorizzare time
.
time
sta per memorizzare il tempo di gioco trascorso, dovrebbe usare un formato a virgola mobile a precisione doppia.
Come già indicato in altre risposte, l'implementazione di un timer può essere effettuata incrementando un valore memorizzato di ciascun frame deltaTime
e confrontandolo con la durata prevista. Per completezza, includerò un codice che è molto simile alle altre risposte:
float elapsed = 0.0f;
float duration = 4.0f;
void update(float deltaTime) {
elapsed += deltaTime;
if (elapsed <= duration) {
// Run code.
elapsed = 0.0f;
// Maybe remove from update loop?
}
}
Il modo in cui vuoi gestire la // Run code.
parte dipende da te. Forse hai una Timer
classe, un'istanza della quale prende un delegate
(C #) o un callback
(C ++) e lo chiama alla scadenza del timer. Inoltre, mettere in pausa il timer è una questione di rimuoverlo dal ciclo di aggiornamento.
Un approccio alternativo è quello di contrassegnare l'ora di inizio del timer e di eseguire invece un calcolo su richiesta del tempo trascorso:
double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;
void start() {
startTime = getTime(); // This is whatever system time call you want to use.
running = true;
}
double getElapsed() {
double elapsed = getTime() - startTime;
return elapsed;
}
Questo stile offre un po 'più di controllo all'utente del timer. La struttura stessa non si preoccupa di cosa fare quando il tempo trascorso raggiunge un certo punto; non si sta nemmeno aggiornando. L'utente può semplicemente interrogare il tempo trascorso quando è necessario. Questo modello ha lo sfortunato effetto collaterale di non essere adatto al debugger. L'ora di sistema continua man mano che il programma viene interrotto su un debugger, quindi timer come questo si comporteranno in modo diverso quando si passa da un programma all'altro. Una potenziale soluzione a ciò è quella di mantenere un valore di tempo trascorso specifico per il programma che viene aggiornato ogni frame usando i delta del tempo di sistema.
Penso che la cosa più importante sia che ci siano due stranezze di tempistica su un computer, specialmente quando si tratta di sviluppo di giochi. Il primo è la precisione in virgola mobile e il secondo è la risoluzione del timer nativo.
Noterai che nel secondo esempio, ho usato un double
tipo invece di a float
, come nel primo esempio (il nome tipografico ovviamente dipende dalla lingua che stai usando). Il motivo di ciò è il secondo esempio è la memorizzazione del tempo di gioco trascorso totale . Se il gioco viene lasciato in esecuzione per un tempo molto lungo, i valori del formato in virgola mobile a precisione singola avranno una precisione insufficiente per misurare accuratamente il tempo trascorso , portando a problemi di stabilità. Il primo esempio va bene usando il float
tipo fintanto che non si prevedono durate enormi.
All'altra estremità dello spettro, se il tempo di aggiornamento che ti aspetti è abbastanza piccolo, potresti non essere in grado di raggiungerlo inizialmente, a seconda di come ottieni il tempo di sistema. I timer dipenderanno spesso dalla risoluzione del timer del sistema operativo su cui si sta eseguendo. Ad esempio, la risoluzione del timer predefinita di Windows 7 e versioni precedenti è 15,6 ms . Ciò significa che la precisione del timer più bassa che è possibile ottenere utilizzando funzioni come timeGetTime
o GetTickCount
è di 15,6 ms, a meno che non si modifichi la risoluzione del timer (ci sono anche dei pericoli associati a questo).
Bene, questo è risultato un po 'lungo, ma queste sono cose importanti da tenere presente quando si implementano i timer.