2010-07-22 9 views
8

Sto scrivendo un gioco ASCII DOS-Prompt della vecchia scuola. Onestamente sto cercando di emulare ZZT per saperne di più su questo marchio di game design (anche se è antiquato)Giochi ASCII DOS - Metodi di rendering

Sto bene, ho fatto funzionare la mia modalità di testo a schermo intero e posso creare mondi e spostare in giro senza problemi, ma non riesco a trovare un metodo di temporizzazione decente per i miei rendering.

So che il mio rendering e il codice di pre-rendering è veloce perché se non aggiungo alcun ritardo() s o (clock() - renderBegin)/CLK_TCK controlla da time.h i rendering sono incredibilmente veloci.

Non voglio usare delay() perché è per la mia piattaforma di conoscenza specifica e per di più non posso eseguire alcun codice mentre ritarda (come l'input e l'elaborazione dell'utente). Così ho deciso di fare qualcosa del genere:

do { 
    if(kbhit()) { 
     input = getch(); 
     processInput(input); 
    } 

    if(clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval) { 
     renderTimer = clock(); 
     render(); 
     ballLogic(); 
    } 
}while(input != 'p'); 

Quale dovrebbe in "teoria" funzionare bene. Il problema è che quando eseguo questo codice (impostando RenderInterval su 0.0333 o 30fps) non riesco quasi ad avvicinarmi a 30fps, ne ottengo più di 18 al massimo.

Ho pensato che forse avrei provato a impostare RenderInterval su 0.0 per vedere se la performance era stata avviata ... no. Ero (con un RenderInterval di 0.0) ottenendo a max ~ 18-20fps.

Anche se forse poiché continuo a chiamare tutti questi metodi clock() e "divide questo per quello" stavo rallentando la CPU, qualcosa di spaventoso, ma quando ho preso il rendering e ballLogic richiama le parentesi dell'istruzione if e imposta RenderInterval su 0.0 Ottengo, ancora, rendi incredibilmente veloci.

Questo non ha senso per me dal momento che se ho lasciato il check in, non dovrebbe funzionare altrettanto lento? Voglio dire che ha ancora a che fare tutti i calcoli

BTW sto compilazione con Borland Turbo C++ V1.01

+1

ZZT! Ho adorato quel gioco. – caf

+0

Io e te entrambi, caf. ('ricerca #throwstar'). @ Parad0x13: Se non ti dispiace allontanarti dal DOS, ho scritto una libreria per emulare questo stile grafico su qualsiasi piattaforma supportata da SDL: http://libfake437.googlecode.com –

+0

Se memorizzi il risultato dall'orologio () "e assegnando il valore memorizzato, salvi una chiamata (il codice più veloce è il codice che non chiami) e sarà più preciso (altrimenti perdi l'intervallo tra la prima volta che hai chiamato" clock() " , ha fatto tutta la matematica e ha gestito il ramo). Questa perdita di precisione renderà il gioco più lento di quello che vuoi, anche se non stai più esaurendo l'utilizzo della CPU. (modifica: haha, ho appena visto la data su questo, vabbè) –

risposta

1
clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC 

sarebbe calcolare un po 'più veloce, forse anche più veloce se si pre-calcolare la parte RenderInterval * CLOCKS_PER_SEC .

+0

Grazie per la tua risposta, vedo l'ottimizzazione. Anche con esso il problema esiste ancora comunque. L'ho appena provato – Parad0x13

+0

Il compilatore esegue tutti i tipi di ottimizzazioni sui loop, che possono creare peculiarità (specialmente se contengono rami): prova ad osservare il codice generato in entrambi i casi. In effetti, il processore fa un lavoro simile (guarda la previsione delle branch). – Ofir

+0

Ho controllato il pre-processore ma non riesco a trovare quali ottimizzazioni sono abilitate. – Parad0x13

0

Che dire di questo: si sta sottostrando da x (= clock()) y (= renderTimer). Sia x ed y sono divisi per CLOCKS_PER_SEC:

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval 

Non sarebbe mor efficiente di scrivere:

(clock() - renderTimer) > RenderInterval 

Il primo problema che ho visto con la divisione era che non si sta andando per ottenere un numero reale da esso, poiché si verifica tra due lunghe intere. Il problema dei secons è che è più efficiente moltiplicare RenderInterval * CLOCKS_PER_SEC e in questo modo eliminarlo, semplificando l'operazione.

L'aggiunta delle parentesi offre maggiore leggibilità. E forse semplificando questa phormula si otterrà più facilmente ciò che sta andando storto.

+0

Ho provato queste ottimizzazioni di formula ma ho continuato a ottenere gli stessi risultati. – Parad0x13

+0

Cosa succede se si forza RenderInterval = 1? – Baltasarq

0

Come hai individuato con la tua domanda più recente, sei limitato da CLOCKS_PER_SEC, che è solo circa 18. Ottieni un frame per valore discreto di clock, motivo per cui sei limitato a 18 fps.

È possibile utilizzare l'intervallo di soppressione verticale dello schermo per la temporizzazione, è tradizione per i giochi in quanto evita "strappo" (dove metà dello schermo mostra una cornice e mostra un altro)

0

ho capito perché non fosse il rendering subito, il timer che ho creato va bene, il problema è che l'attuale clock_t è solo accurato a .054547XXX o giù di lì e quindi ho potuto renderizzare solo a 18fps. Il modo in cui risolverei questo è usando un orologio più accurato ... che è tutta un'altra storia

2

La migliore esperienza di gioco si ottiene solitamente sincronizzando con la ritraccia verticale del monitor. Oltre a fornire i tempi, questo renderà il gioco più fluido sullo schermo, almeno se si dispone di un monitor CRT collegato al computer.

In modalità testo 80x25, il ritracciamento verticale (su VGA) si verifica 70 volte/secondo. Non ricordo se la frequenza fosse la stessa su EGA/CGA, ma sono abbastanza sicuro che fosse Hercules e MDA a 50 Hz. Misurando la durata di, diciamo, 20 fotogrammi, dovresti avere una stima sufficientemente buona di quale frequenza hai a che fare.

Diamo il ciclo principale sia someting come:

while (playing) { 
    do whatever needs to be done for this particular frame 
    VSync(); 
    } 

    ... /* snip */ 

    /* Wait for vertical retrace */ 
    void VSync() { 
    while((inp(0x3DA) & 0x08)); 
    while(!(inp(0x3DA) & 0x08)); 
    }