2010-07-22 15 views
8

Estoy escribiendo un juego ASCII DOS-Prompt de la vieja escuela. Honestamente estoy tratando de emular ZZT para aprender más sobre esta marca de diseño de juegos (incluso si es anticuado)Juegos ASCII DOS - Métodos de representación

Estoy bien, tengo mi modo de texto de pantalla completa para trabajar y puedo crear mundos y moverme alrededor sin problemas PERO no puedo encontrar un método de tiempo decente para mis renders.

Sé que mi renderización y el código de pre representación son rápidos porque si no agrego ningún delay() s o (clock() - renderBegin)/CLK_TCK comprueba desde time.h que los renders son increíblemente rápidos.

No quiero utilizar delay() porque es mi plataforma de conocimiento específica y además de eso no puedo ejecutar ningún código mientras se demora (como la entrada y el procesamiento del usuario). Así que decidí hacer algo como esto:

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

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

Lo que debería funcionar en "teoría" bien. El problema es que cuando ejecuto este código (estableciendo RenderInterval en 0.0333 o 30 fps) no obtengo DONDEQUIERA cerca de 30 fps, obtengo más como 18 al máximo.

Pensé que tal vez intentaría configurar el RenderInterval en 0.0 para ver si el rendimiento empezaba ... no lo hizo. Estaba (con un RenderInterval de 0.0) obteniendo un máximo de ~ 18-20 fps.

Creo que, como estoy continuamente llamando a todos estos métodos clock() y "divide esto por eso", estaba ralentizando la CPU algo aterrador, pero cuando tomé el renderizado y ballLogic invocó los corchetes de la sentencia if y establezco RenderInterval en 0.0 obtengo, de nuevo, renderizaciones sorprendentemente rápidas.

Esto no tiene sentido para mí, ya que si salí de la verificación de si, ¿no debería funcionar igual de lento? Quiero decir que todavía tiene que hacer todos los cálculos

Por cierto que estoy compilando con de Turbo C++ V1.01

+1

ZZT! Me encantó ese juego. – caf

+0

Tú y yo ambos, caf. ('#throwstar seek'). @ Parad0x13: Si no te importa alejarte de DOS, escribí una biblioteca para emular este estilo gráfico en cualquier plataforma compatible con SDL: http://libfake437.googlecode.com –

+0

Si almacenas el resultado de 'clock () 'y asigne el valor almacenado, guardará una llamada (el código más rápido es el que no llama) y será más preciso (de lo contrario, perderá el tiempo entre la primera llamada' reloj() ' , hizo todas las matemáticas y manejó la rama). Esta pérdida de precisión hará que el juego funcione más despacio de lo que desee, incluso si ya no está maximizando el uso de la CPU. (Editar: jaja, acabo de ver la fecha en esto, bueno) –

Respuesta

1
clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC 

sería calcular un poco más rápido, posiblemente incluso más rápido si se pre-calcular la parte RenderInterval * CLOCKS_PER_SEC .

+0

Gracias por su respuesta, veo la optimización. Incluso con eso, el problema aún existe. Lo intenté sin embargo – Parad0x13

+0

El compilador realiza todo tipo de optimizaciones en bucles, lo que puede crear peculiaridades (especialmente si contienen ramas). Intente ver el código generado en ambos casos. De hecho, el procesador realiza un trabajo similar (consulta la predicción de bifurcación). – Ofir

+0

Comprobé el preprocesador pero no puedo averiguar qué optimizaciones están habilitadas. – Parad0x13

0

Qué tal esto: usted está restando de x (= clock()) y (= renderTimer). X e Y están siendo divididas por CLOCKS_PER_SEC:

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval 

¿No sería mor efficiente para escribir:

(clock() - renderTimer) > RenderInterval 

El primer problema que vi con la división fue que no vas para obtener un número real, ya que ocurre entre dos entradas largas. El segundo problema es que es más eficiente multiplicar RenderInterval * CLOCKS_PER_SEC y así deshacerse de él, simplificando la operación.

La adición de los corchetes le da más legibilidad. Y tal vez, al simplificar esta fórmula, será más fácil lo que va mal.

+0

Intenté estas optimizaciones de fórmula, pero continué teniendo los mismos resultados. – Parad0x13

+0

¿Qué sucede si fuerza RenderInterval = 1? – Baltasarq

0

Como has visto con tu pregunta más reciente, estás limitado por CLOCKS_PER_SEC que tiene solo 18 años. Obtienes un fotograma por valor discreto de reloj, por lo que estás limitado a 18 fps.

Se puede usar el intervalo de borrado vertical de la pantalla para medir el tiempo, es tradicional para los juegos, ya que evita "desgarro" (donde la mitad de la pantalla muestra un cuadro y la otra mitad muestra otra)

0

me di cuenta de por qué no fue renderizado de inmediato, el temporizador que creé está bien, el problema es que el clock_t real solo tiene una precisión de .054547XXX, y por eso solo pude renderizar a 18 fps. La forma en que arreglaría esto es usando un reloj más preciso ... que es una historia completamente diferente

2

La mejor experiencia de juego generalmente se logra sincronizando con el retroceso vertical del monitor. Además de proporcionar el tiempo, esto también hará que el juego sea más fluido en la pantalla, al menos si tienes un monitor CRT conectado a la computadora.

En el modo de texto 80x25, el retorno vertical (en VGA) se produce 70 veces/segundo. No recuerdo si la frecuencia era la misma en EGA/CGA, pero estoy bastante seguro de que era de 50 Hz en Hercules y MDA. Al medir la duración de, por ejemplo, 20 cuadros, debe tener una estimación suficientemente buena de la frecuencia con la que está tratando.

Vamos a ser el bucle principal calle detrás como:

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)); 
    } 
Cuestiones relacionadas