Utilizzo del tempo di inattività nei giochi a turni (RPG) per l'aggiornamento


9

Se giochi a un gioco di ruolo a turni, ci saranno grandi periodi di tempo in cui non accade nulla perché il gioco scorre in loop su "wait_for_player_input". Naturalmente sembra ragionevole usare questa volta per aggiornare le cose.

Tuttavia, questo sembra immediatamente suggerire che avrebbe bisogno di essere thread. Questo tipo di design è possibile in un singolo thread?

loop:  
if not check_something_pressed:  
    update_a_very_small_amount  
else  
  keep going

Ma se diciamo che 'a_very_small_amount' aggiorna solo un singolo oggetto per ogni ciclo, sarà molto lento nell'aggiornamento.

Come lo faresti, preferibilmente in un singolo thread?

EDIT: Ho etichettato questo linguaggio agnostico in quanto sembra la cosa sensata, anche se qualsiasi cosa più specifica di Python sarebbe eccezionale. ;-)

Seconda modifica: questo gioco non prevede di avere componenti animati; cioè, lo sto attualmente eseguendo come input di attesa per il giocatore, quindi aggiorno tutto e disegno. Quindi, piuttosto che X FPS, dipende dalla velocità dell'utente.

Risposte:


7

Sì, è possibile farlo in un singolo thread. In generale, però, ti consigliamo di aggiornare gli oggetti ogni frame e non solo quando ci sono cicli di riserva. Le animazioni e i movimenti verranno disconnessi dalla frequenza dei fotogrammi e, in caso contrario, sembreranno piuttosto instabili. Se stai parlando di più sugli aggiornamenti AI o qualcos'altro che non deve essere in tempo reale, metterei un timer su di esso. Dovresti sapere qual è la frequenza dei fotogrammi target e il tempo di inattività sarà quello che rimane dopo che tutto il resto è stato completato.

Supponiamo che tu stia prendendo di mira 60 FPS per il tuo gioco. Ciò lascia 16.667 ms per eseguire tutto il lavoro necessario per eseguire ogni frame. All'inizio del gioco, ottieni l'ora corrente usando il timer con la più alta risoluzione disponibile, aggiungi 16.667 ms e salvalo da qualche parte. Penso che la funzione in Python sia time () anche se è passato un po 'di tempo da quando ho lavorato nella lingua. Al termine dell'elaborazione, immettere un ciclo che controlla l'ora corrente rispetto all'ora registrata. Se l'ora corrente è inferiore all'ora di fine del frame, update_a_very_small_amount. Non mi preoccuperei molto dell'elaborazione che va oltre la fine del frame poiché il tuo piccolo aggiornamento dovrebbe essere rapido da elaborare. Sarebbe solo un leggero ritardo all'inizio del fotogramma successivo e sembra che tu abbia abbastanza tempo di inattività per gestirlo.

Al termine dell'elaborazione del frame, aggiungere 16.667 ms al tempo memorizzato per la fine dell'ultimo frame per scoprire dove dovrebbe trovarsi la fine del frame successivo. Se si utilizza l'ora corrente + 16.667 ms e l'elaborazione procede, la fine del fotogramma successivo verrà espulsa per un periodo di tempo trascorso dall'ultimo fotogramma.

Ri: Seconda modifica

Per chiarire, qui uso il termine frame rate per indicare un'iterazione attraverso il ciclo principale. Se è basato sulla velocità di input dell'utente, immagino che il tuo obiettivo sia semplicemente quello di rendere il gioco reattivo. Altrimenti potresti semplicemente controllare l'input e aggiornare tutto ogni volta attraverso il ciclo anche se ci vogliono 10 secondi per farlo. Per farlo sembrare reattivo, probabilmente vorrai verificare l'input circa 20 volte al secondo, il che fornisce un frame rate effettivo di 20 FPS, anche se non stai effettivamente disegnando questi frame. Ciò ti darebbe 50 ms per aggiornare le cose prima di dover controllare nuovamente l'input.


2

Per Python, in particolare, puoi provare a utilizzare Coroutine per eseguire calcoli su più chiamate di aggiornamento.

... le coroutine sono componenti del programma che generalizzano le subroutine per consentire più punti di ingresso per sospendere e riprendere l'esecuzione in determinate posizioni ...

PEP-0342 illustra l'implementazione coroutine in Python.

È possibile creare il proprio scheduler e attività che possono simulare il multithreading su un singolo thread. Questo è lo stesso modo in cui i framework Javascript consentono l'elaborazione multithread come l'elaborazione anche se Javascript viene eseguito su un singolo processo.


1

Sì questo è possibile. Il tuo gioco avrà una sorta di loop di gioco principale. Qualcosa come questo:

while(gameRunning)
{
  checkUserInput()
  updateGame()
  renderGame()
}

In updateGame puoi scorrere gli oggetti del tuo gioco e aggiornarli "un po '". Se stai eseguendo calcoli pesanti in questo metodo, il gioco si bloccherà semplicemente. Quindi è necessario un modo per suddividere questi calcoli per eseguire diverse iterazioni del ciclo di gioco.

Come dividerli, dipende dal tipo di gioco che stai costruendo. Supponiamo di avere una routine di ricerca percorsi che utilizza A * per calcolare un percorso attraverso un labirinto. Dovresti interrompere l'algoritmo dopo un certo periodo di tempo o dopo un determinato numero di iterazioni, mantenere il percorso calcolato finora e restituire il controllo al loop del gioco. La ricerca del percorso continuerà la prossima volta che viene chiamato updateGame. Puoi anche spostare il personaggio lungo il percorso parziale mentre è ancora in fase di calcolo.

La maggior parte delle volte non devi preoccuparti che la chiamata di updateGame impieghi troppo tempo.

"L'ottimizzazione precoce è la radice di tutti i mali!"
Se si verifica un collo di bottiglia nelle prestazioni nella routine di aggiornamento, è il momento di indagare e ottimizzare. Dal momento che non puoi sapere in anticipo quali parti del tuo gioco impiegheranno più tempo per il calcolo e potrebbero perdere tempo a ottimizzare le cose sbagliate.


1

Il modo in cui capisco la tua domanda è che sostanzialmente stai chiedendo del multitasking cooperativo.

L'infrastruttura di base sarebbe un elenco di puntatori di funzioni, tutti chiamati in modo round robin (a meno che non sia richiesta una definizione delle priorità più sofisticata) e tutte queste funzioni farebbero "un po 'di lavoro", abbastanza piccolo da non causare il gioco diventare pigro. L'ho fatto in DOS prima che i thread fossero caldi e anche su dispositivi mobili che non supportavano il threading.

Una domanda migliore, secondo me, è cosa fare mentre si aspetta che il giocatore si muova. Quali tipi di cose sarebbero così ad alta intensità di processore da non poter essere eseguiti al volo comunque, mentre, allo stesso tempo, essendo così facoltativi che se il giocatore preme semplicemente un tasto di spostamento abbastanza velocemente, il gioco non ha tempo di elaborare questi. Quindi, cose come il calcolo di A * per un paio di migliaia di IA sono fuori.

La soluzione migliore, secondo me, è semplicemente cedere / dormire e lasciare che la gestione dell'alimentazione del computer faccia il suo lavoro. Agli utenti di laptop piacerà di più.

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.