2009-03-25 10 views
6

Ogni tutorial di gioco e framework di gioco (anche il nuovissimo framework XNA) iniziano con un ciclo senza fine che ha un equivalente di DoEvents() per impedire il blocco del sistema operativo.Migliori circuiti di gioco di loop infinito + blocco?

Arrivando da una prospettiva non basata sul gioco, sento che questo tipo di codice ha un odore piuttosto funky.
Non ci sono alternative migliori?

--EDIT--
un sacco di risposte dicono ogni programma è fondamentalmente un ciclo. È vero, ma ritengo che il ciclo debba essere eseguito dal sistema operativo, non da te. Solo il sistema operativo ha tutte le informazioni di cui ha bisogno per distribuire le sue risorse in modo ottimale. O mi manca un punto importante qui?

+0

Sì, ti manca l'importante distinzione che un gioco non è un servizio OS. – Hejazzman

risposta

5

ogni Windows applicazione ha al suo interno un ciclo che sembra qualcosa di simile:

BOOL bRet; 

while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) 
{ 
    if (bRet == -1) 
    { 
     // handle the error and possibly exit 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

È compito dell'applicazione - non del sistema operativo - per garantire che i messaggi vengono inviati.

Come probabilmente sapete, i giochi primi di Windows utilizzato un metodo alternativo in cui, invece di chiamare la GetMessage funzione di bloccaggio, che avrebbero chiamato PeekMessage, e quindi chiamare ciclo di elaborazione principale del gioco se non ci fosse alcun messaggio da gestire. Sono state utilizzate varie forme di ritardi per cercare di ottenere un frame rate adeguato senza utilizzare il 100% di CPU. Semplicemente non c'era un timer abbastanza buono per ottenere una frequenza fotogrammi uniforme.

Oggi, potrebbe non essere necessario scrivere esplicitamente un ciclo che chiama DoEvents. È possibile che sia ora possibile ottenere una frequenza di fotogrammi uniforme utilizzando i timer di pool di timer incorporati (esposti in .NET da System.Threading.Timer e spostati da System.Timers.Timer).

Come ricordo, c'erano anche problemi con ottenere eventi mouse e tastiera in modo tempestivo. Abbiamo utilizzato l'accesso diretto alla tastiera e al mouse piuttosto che a seconda del ciclo dei messaggi, perché il ciclo dei messaggi era spesso troppo lento e talvolta ci causava la perdita di informazioni.

Non ho scritto giochi in un numero di anni, e non so come sia .NET come piattaforma di giochi. È possibile che l'input sia ancora un problema - che la coda dei messaggi semplicemente non sia abbastanza veloce da fornire la risposta fulminea che gli sviluppatori di giochi vogliono. Quindi ignorano la coda dei messaggi per le attività critiche.

+0

In realtà stavo pensando se sarebbe stato necessario creare un timer che conoscesse la frequenza dello schermo per creare fotogrammi. In questo modo non vengono mai eseguite esecuzioni inutili. Anche l'idea coniata da @Bryan Parker di avere il disegno in un thread separato per staccarlo dal resto (logica di gioco/IO) ... –

+0

... sembra una buona idea. Non so se è pratico, comunque. –

+1

Adesso la maggior parte dei giochi ha il rendering in una discussione separata. E vuoi essere in grado di disaccoppiare i tuoi aggiornamenti da vsync per il test delle prestazioni (tra gli altri motivi) – BigSandwich

1

Tutti i programmi in esecuzione non terminano mai. Anche se in alcuni casi non si interagisce con il ciclo (come nella programmazione Web o altri programmi minori)

Il sistema operativo è un ciclo in attesa di comandi di input. Lo stesso con un gioco. Un server web è un ciclo in attesa di richieste.

Un grande spiegazione è dall'utente slim on one of my own questions.

+0

Hai praticamente ragione, anche se questo è vero solo per i programmi basati su GUI. per applicazioni banali e da linea di comando puoi facilmente andare via senza un ciclo principale. –

+0

Aggiunto un chiarimento. –

+0

Leggi il tuo post e in effetti l'ho capito. Ma dal momento che il sistema operativo sta già eseguendo questo ciclo, non è una buona idea collegarsi a quel ciclo (utilizzare gli eventi del sistema operativo) piuttosto che creare il proprio loop nel ciclo del sistema operativo? –

0

code di messaggi sono cicli infiniti pure che rende tutti i programmi esempio un loop infinito.

-3

se non sentirsi a proprio agio su di esso, pacchetto con classe e l'interfaccia,

questo è quello che diciamo "principio apri e chiudi": aprire l'interfaccia non è mai cambiato, chiudere la parte sporca.

perché utilizziamo il ciclo? perché è la struttura di base del nostro computer!

+0

Temo che ci sia un errore di comunicazione. So come nascondere tutti i brutti bit, ma la domanda è: perché dovremmo implementare un ciclo all'interno del ciclo del sistema operativo. –

1

Il ciclo migliore è un ciclo infinito con chiamata di blocco per inviare eventi/messaggi. Se non c'è nulla da fare, non dovresti davvero dormire, ma bloccare mentre aspetti il ​​sistema operativo. Ma se il sistema operativo non blocca effettivamente quando si esegue il polling degli eventi, la sospensione tra il polling è l'unica soluzione per impedire l'utilizzo della CPU al 100%.

+0

Ok, questo è quello che intendevo con il sonno. (il vecchio DoEvents). Cambierà post per riflettere questo. –

1

Non vedo come potrebbe essere fatto in modo molto diverso?

L'esecuzione del programma si verifica all'interno di una discussione (o più thread se siete fantasiosi). Avere un gameloop (o una pompa GetMessage/DispatchMessage per win32) significa attendere che l'evento si verifichi e quindi gestirli. L'alternativa sarebbe registrare i callback, quindi chiamare un HandleAllMyMessages(), che internamente farebbe praticamente la stessa cosa ... e che non ti avrebbe davvero comprato nulla.

Il sistema operativo non è in grado di dividere magicamente il programma in più thread, poiché non ha alcuna conoscenza di ciò che si desidera fare all'interno di tali thread. Creare un nuovo thread per ogni messaggio in arrivo sarebbe un inferno per le prestazioni e la sincronizzazione.

1

Su Win32 Io uso un timer MultiMedia di chiamare il mio segno di spunta gamelogic ...

// request 1ms period for timer 
g_mmTimer = timeBeginPeriod(1); 
if (g_mmTimer != TIMERR_NOERROR) 
    return false; 

//start game loop event timer/thread 
g_mmTimer = timeSetEvent(10, 10, DoUpdate, 0, TIME_PERIODIC); 

Opzionalmente, si può fare tutto il disegno in un altro thread in modo che la logica del gioco è automaticamente indipendente dal frame rate.

2

Games (nella maggior parte dei casi) sono simulazioni. Tradizionalmente questo significa che si aggiorna la simulazione, si presenta il suo stato corrente (ad es. Renderizza grafica) e si ripete. La rappresentazione naturale per questo è un loop.

La pompa di messaggi Win32 d'altra parte è una stranezza specifica della piattaforma, orientata verso le applicazioni event-driven che costituiscono la maggior parte delle app su Windows. Non è affatto lo standard per le applicazioni su tutte le piattaforme, quindi non sorprende che non tutto il software si adatti perfettamente al modello. Quindi per modificare un programma tipico per adattarlo al modello Win32, in genere si esaurisce la coda in una volta sola, una volta per iterazione del ciclo, utilizzando PeekMessage finché non è vuoto. O si mette quella logica in un thread separato e si utilizza GetMessage come appropriato.

Per la maggior parte dei giochi con prestazioni in mente non esiste un altro modo pratico per farlo. In primo luogo, se provassi a rendere il gioco guidato dagli eventi invece del sondaggio, avresti bisogno di tempi di risoluzione più elevati di quelli che Windows può affidarti in modo affidabile se vuoi mantenere le alte prestazioni su cui molti giochi vanno. In secondo luogo, Windows è solo una delle piattaforme per cui i giochi sono stati scritti, e rielaborare il gioco per adattarsi bene al modello Win32 sarà solo un inconveniente per le piattaforme di gioco dedicate che prevedono invece il ciclo di gioco canonico.

Infine, le preoccupazioni relative a "prendere il 100% della CPU" non sono corrette. La maggior parte dei giochi moderni sono progettati per essere utilizzati in modalità a schermo intero con accesso hardware esclusivo, non per essere solo una delle numerose altre applicazioni coesistenti. I clienti di tali giochi richiedono effettivamente che il gioco utilizzi maggiormente il loro hardware e questo non può essere fatto se ci sono chiamate intenzionali Sleep() o gli aggiornamenti dipendono da timer esterni che riattivano l'applicazione N volte al secondo. Ovviamente ci sono eccezioni per molti giochi, ad es. quelli che sono progettati per funzionare principalmente in una finestra, ma è importante notare la differenza.

+0

Risposta e panoramica fantastiche. –

+0

Prendere il 100% della CPU è sicuramente una preoccupazione valida e qualcosa da evitare. Anche quando sei a foreground a schermo intero, non vuoi sprecare cicli di CPU. Interferisce sempre più con la gestione energetica ogni anno che passa. Quando hai scritto la tua risposta, sarebbe stata solo una preoccupazione per i laptop (che è ancora una ragione sufficiente per non masterizzare la CPU). Oggi, sposterà il core della CPU in Turbo Boost, riducendo la potenza disponibile per la GPU integrata. Quindi la tua idea di accumulare tutte le risorse per il tuo gioco diminuisce le sue prestazioni. -1 –

+0

@BenVoigt - Questo è un punto valido, ma dipende dalla piattaforma a cui stai mirando. I giochi AAA che non sono destinati esclusivamente a piattaforme mobili o portatili non introdurranno deliberatamente cicli di sonno per nessuna ragione e aumenteranno l'elaborazione per riempire le risorse disponibili della CPU. Più precisamente, non ci si aspetta che producano buone prestazioni con le GPU integrate: sono cittadini di seconda classe per quanto riguarda il software di gioco. Ma se stai mirando al mobile ... questa è una storia diversa. – Kylotan

0

MsgWaitForMultipleEvents combina funzionalità GetMessage/PeekMessage con un timeout e la capacità di aspettare per oggetti del kernel, come ad esempio un WaitableTimer.

Ho utilizzato CreateWaitableTimer per impostare la frequenza di fotogrammi desiderata insieme a MsgWaitForMultipleEvents per l'invio di messaggi con grande successo per un'animazione molto fluida in passato, senza attività di attesa. Vorrei che altri sistemi operativi avessero qualcosa di così bello.