Come fare accadere qualcosa ogni N secondi nel gioco?


8

Voglio che succeda qualcosa ogni N secondi, come lo farei? Magari usa un timer ma come?


Ho reso la tua domanda più generica poiché penso che sia più utile per più persone in questo modo.
MichaelHouse

Sulla base dei commenti su una delle risposte, non credo che il poster stia cercando il bit del timer, ma come cambiare il frame dello sprite. Dipende maggiormente dalla piattaforma di cui stiamo parlando. Indipendentemente da ciò, ora che la domanda è stata modificata, non rappresenta ciò che sta davvero chiedendo. Java 2D è stato importante per la domanda che sta cercando di porre.
prototipo

Cambiare lo sprite e farlo accadere ogni 5 secondi non è correlato e dovrebbe essere posto come domande diverse. Per favore, fai una nuova domanda su come cambiare lo sprite. Assicurati di includere ciò che hai provato e che non funziona.
MichaelHouse

Risposte:


14

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 deltaTimevariabile. 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 .


È in qualche modo tecnico preferibile avviare un timer esplicito come nella risposta di @Josh?
Jack M,

@JackM Dipende dall'implementazione del timer. Il motivo per cui ho risposto in questo modo è perché il linguaggio è agnostico e molto semplice da implementare.
MichaelHouse

1
@JackM: è anche preferibile eseguire mai un debugger. Il tempo di gioco accumulato può fermarsi quando si colpisce un breakpoint anziché far scadere tutti i timer e continuare a sparare all'istante.
Ben Jackson,

Bisogna stare attenti, perché il gioco potrebbe bloccarsi per esempio e le zecche potrebbero andare perse. Pertanto si deve invocare l'azione di un timer per ogni tick con il delta specificato che è passato e non solo una volta ecc.
Christian Ivicevic,

Questo metodo non si basa sul conteggio delle zecche, ma sul delta time. Se esiste un frame extra lungo, anche il tempo delta è extra long. Tuttavia, in molti casi è preferibile limitare il delta time, frame extra lunghi possono causare problemi di fisica e simili. Questo metodo è quindi superiore al solo utilizzo dell'ora corrente meno l'ora di inizio poiché si sincronizzerà meglio con gli altri calcoli nel gioco quando si limita l'intervallo di tempo delta.
MichaelHouse

3

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.


1
Buona risposta. Ciò potrebbe avere problemi di threading in alcune lingue (ad es. .NET) in cui un timer è implementato in un thread separato dal tuo loop di gioco.
ashes999,

1
È anche importante notare qui che se timesta per memorizzare il tempo di gioco trascorso, dovrebbe usare un formato a virgola mobile a precisione doppia.
kevintodisco,

Questi sono buoni punti, li aggiungerò alla risposta.
Josh,

2

Come già indicato in altre risposte, l'implementazione di un timer può essere effettuata incrementando un valore memorizzato di ciascun frame deltaTimee 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 Timerclasse, 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 doubletipo 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 floattipo 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 timeGetTimeo 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.


grazie ma ora come fare quel bit ma come cambierei lo sprite indietro e
froward

@ user2957632 Non è questa la domanda che ti stai ponendo in questo momento. Per favore, chiariscilo.
kevintodisco,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.