SYNCronizar velocidad juego (variable FRAMES)
- Hark0
- Mensajes: 683
- Registrado: 27 Sep 2015, 00:31
- Ubicación: Cornellà de Llobregat - BCN
- Contactar:
SYNCronizar velocidad juego (variable FRAMES)
Buenas!
No se si lo estoy haciendo como toca, pero os comento aquí a ver si alguien tiene alguna solución / alternativa para ajustar la velocidad de un juego.
Actualmente estoy haciendo lo siguiente (z88dk):
Inicio una variable para leer el contador FRAMES del sistema:
unsigned int dir_peek_FRAMES;
unsigned char reloj_A;
unsigned char reloj_B;
unsigned char reloj_diff;
Inicio más cosas y me meto en el mainloop, que contiene rutina de pintado, control teclado y lógica programa.
Antes del mainloop hago:
dir_peek_FRAMES = 23672; // Dirección variable FRAMES ZX-Spectrum
*dir_peek_FRAMES = 0; // "POKE" a esa dirección con valor 0
Inicio mainloop
reloj_A = *dir_peek_FRAMES;
// RUTINAS PROPIAS DE RENDER, CONTROL, LOGICA...
reloj_B = *dir_peek_FRAMES;
reloj_diff = reloj_B - reloj_A;
reloj_A =0;
reloj_B =0;
*dir_peek_FRAMES = 0;
Fin mainloop
Y obtengo esto que veis... me tarda 13 "FRAMES" en realizar todo el bucle, ver animación GIF:
Vale, hasta aqui todo bien como veis... PERO... va demasiado rápido (el GIF no le hace justicia)... y el tema de añadir WAIT no me convence...
¿Alguna idea para aprovechar ese timer de cara a que todo esté sincronizado?
Espero haberme explicado, anticipadas
No se si lo estoy haciendo como toca, pero os comento aquí a ver si alguien tiene alguna solución / alternativa para ajustar la velocidad de un juego.
Actualmente estoy haciendo lo siguiente (z88dk):
Inicio una variable para leer el contador FRAMES del sistema:
unsigned int dir_peek_FRAMES;
unsigned char reloj_A;
unsigned char reloj_B;
unsigned char reloj_diff;
Inicio más cosas y me meto en el mainloop, que contiene rutina de pintado, control teclado y lógica programa.
Antes del mainloop hago:
dir_peek_FRAMES = 23672; // Dirección variable FRAMES ZX-Spectrum
*dir_peek_FRAMES = 0; // "POKE" a esa dirección con valor 0
Inicio mainloop
reloj_A = *dir_peek_FRAMES;
// RUTINAS PROPIAS DE RENDER, CONTROL, LOGICA...
reloj_B = *dir_peek_FRAMES;
reloj_diff = reloj_B - reloj_A;
reloj_A =0;
reloj_B =0;
*dir_peek_FRAMES = 0;
Fin mainloop
Y obtengo esto que veis... me tarda 13 "FRAMES" en realizar todo el bucle, ver animación GIF:
Vale, hasta aqui todo bien como veis... PERO... va demasiado rápido (el GIF no le hace justicia)... y el tema de añadir WAIT no me convence...
¿Alguna idea para aprovechar ese timer de cara a que todo esté sincronizado?
Espero haberme explicado, anticipadas
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.
Re: SYNCronizar velocidad juego (variable FRAMES)
Una cosilla. El "tiempo" (número de ticks de 1/50 segundo) se almacena en las direcciones 23672 a 23674. Es decir es un dato de 24 bits... de 0 a 16.777.216. Con este rango de valores cicla cada 93 horas aproximadamente.
Todo esto suponiendo el funcionamiento a 50Hz. Por tanto no sé si tal y como coges el valor de esas direcciones de memoria estás teniendo en cuenta esto. Porque si no ese cálculo de "frames" que haces puede no ser del todo correcto.
Imagino que nadie va a tener su Spectrum arrancado casi 4 días (93 horas) ya que sino tendrías que complicar el cálculo de ciclos dado que el valor de esa variable del sistema pasará de su valor máximo a 0 cada 93 horas desde que se encendió el Spectrum.
Dicho esto, y por los datos que das tu bucle principal tarda 13/50 de segundo en ejecutarse. Si estás haciendo un pintado en pantalla cada pasada del bucle no me cuadra algo ya que estaría pintando como unas 4 veces por segundo... es decir, debería verse todo a 4 FPS. Y da la sensación de que es mucho más. Por eso algo no me cuadra en el dato ese de 13 "frames". O algo se me está escapando...
Todo esto suponiendo el funcionamiento a 50Hz. Por tanto no sé si tal y como coges el valor de esas direcciones de memoria estás teniendo en cuenta esto. Porque si no ese cálculo de "frames" que haces puede no ser del todo correcto.
Imagino que nadie va a tener su Spectrum arrancado casi 4 días (93 horas) ya que sino tendrías que complicar el cálculo de ciclos dado que el valor de esa variable del sistema pasará de su valor máximo a 0 cada 93 horas desde que se encendió el Spectrum.
Dicho esto, y por los datos que das tu bucle principal tarda 13/50 de segundo en ejecutarse. Si estás haciendo un pintado en pantalla cada pasada del bucle no me cuadra algo ya que estaría pintando como unas 4 veces por segundo... es decir, debería verse todo a 4 FPS. Y da la sensación de que es mucho más. Por eso algo no me cuadra en el dato ese de 13 "frames". O algo se me está escapando...
- Hark0
- Mensajes: 683
- Registrado: 27 Sep 2015, 00:31
- Ubicación: Cornellà de Llobregat - BCN
- Contactar:
Re: SYNCronizar velocidad juego (variable FRAMES)
Estuve mirando las 3 posiciones de memoria que "gestionan" FRAMES... como bien comentas....
La dirección 23672 es la que cambia más rápido... cuando alcanza 256, pasa a 0
y suma +1 en la dirección 23673... cuando éste alcanza 256, pasa a 0
y suma +1 en la dirección 23674
Con lo que... he pensado usar solo la 23672... inciandolo a 0 en cada bucle.
..............
¿Qué hace mi programa en el mainloop?
1. Pinta la pantalla (NO ENTERA, sólo las zonas que cambian)
2. Comprueba que haya evento en marcha (tecla pulsada o acción asignada al personaje). Si hay un evento asignado al personaje NO leo el teclado.
3. Lógica + IA del juego
4. Goto 1
Lo que pretendo es "ralentizar" el loop ya que evidentemente no tarda lo mismo en pintar 4 tiles, que pintar 30...
No se si te aclaro algo.
La dirección 23672 es la que cambia más rápido... cuando alcanza 256, pasa a 0
y suma +1 en la dirección 23673... cuando éste alcanza 256, pasa a 0
y suma +1 en la dirección 23674
Con lo que... he pensado usar solo la 23672... inciandolo a 0 en cada bucle.
..............
¿Qué hace mi programa en el mainloop?
1. Pinta la pantalla (NO ENTERA, sólo las zonas que cambian)
2. Comprueba que haya evento en marcha (tecla pulsada o acción asignada al personaje). Si hay un evento asignado al personaje NO leo el teclado.
3. Lógica + IA del juego
4. Goto 1
Lo que pretendo es "ralentizar" el loop ya que evidentemente no tarda lo mismo en pintar 4 tiles, que pintar 30...
No se si te aclaro algo.
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.
Re: SYNCronizar velocidad juego (variable FRAMES)
Se me ocurre que quizá puedes calcular los "frames" que tarda tu rutina de pintado, que serán variables en función de lo que tenga que pintar.
Con ese dato meter un retardo, o no, para ralentizar el bucle si va demasiado rápido. O no meterlo si la carga de pantalla a pintar es mucha.
La opción para no meter retardos o "waits" sería usar interrupciones. Y poner la rutina de pintado que sea llamada cada 1, 2, 3 interrupciones. Si tiene algo que pintar que lo pinte.
Son ideas al "azar". Que sin saber más de la lógica del juego pues puede que no te sirvan de nada.
Con ese dato meter un retardo, o no, para ralentizar el bucle si va demasiado rápido. O no meterlo si la carga de pantalla a pintar es mucha.
La opción para no meter retardos o "waits" sería usar interrupciones. Y poner la rutina de pintado que sea llamada cada 1, 2, 3 interrupciones. Si tiene algo que pintar que lo pinte.
Son ideas al "azar". Que sin saber más de la lógica del juego pues puede que no te sirvan de nada.
Re: SYNCronizar velocidad juego (variable FRAMES)
Se me ocurre otra cosa. Igual el tema está en que los frames de animación son los que van rápidos.
En ese caso calcula cada cuantos 1/50 de segundo debería avanzar cada frame de animación. Por ejemplo cada 20/50. Para que la animación vaya a una velocidad constante.
Cuenta con el temporizador si se ha llegado al 50avo de segundo correspondiente y avanza el frame.
No sé si me explico.
En ese caso calcula cada cuantos 1/50 de segundo debería avanzar cada frame de animación. Por ejemplo cada 20/50. Para que la animación vaya a una velocidad constante.
Cuenta con el temporizador si se ha llegado al 50avo de segundo correspondiente y avanza el frame.
No sé si me explico.
Re: SYNCronizar velocidad juego (variable FRAMES)
¿Estas cosas no se hacen normalmente poniendo un HALT y punto?
Quiero decir, la variable frames se actualiza cada 0,020 segundos, es decir, 50 veces por segundo, es decir, lo hace la rutina de interrupción. un HALT lo que hace es esperar a una interrupción (o reset), así el bucle sería:
1. haz tu rollo
2. halt
3. goto 1
Eso sí, "tu rollo" tiene que caber en 0,020 segundos si quieres máxima velocidad dentro de la sincronización. Si tardara 0,025 el juego iria realmente a un "tu rollo" cada 0,040 segundo, lo cual tampoco tiene por que ser malo . Es más, si a 0,040 te parece que va rapido, supongo que puede poner dos HALT.
Supongo que en Z88dk habrá algo que haga un halt, o sino se podrá hacer una funcion en assembler que tenga un halt (o incluso ponerlo inline)
(o como se ponga)
Lo mismo me estoy pasando de listo, pero todo ese rollo de andar mirando la variable frames me parece un poco rebuscado.
Quiero decir, la variable frames se actualiza cada 0,020 segundos, es decir, 50 veces por segundo, es decir, lo hace la rutina de interrupción. un HALT lo que hace es esperar a una interrupción (o reset), así el bucle sería:
1. haz tu rollo
2. halt
3. goto 1
Eso sí, "tu rollo" tiene que caber en 0,020 segundos si quieres máxima velocidad dentro de la sincronización. Si tardara 0,025 el juego iria realmente a un "tu rollo" cada 0,040 segundo, lo cual tampoco tiene por que ser malo . Es más, si a 0,040 te parece que va rapido, supongo que puede poner dos HALT.
Supongo que en Z88dk habrá algo que haga un halt, o sino se podrá hacer una funcion en assembler que tenga un halt (o incluso ponerlo inline)
Código: Seleccionar todo
ASM
{
HALT
}
Lo mismo me estoy pasando de listo, pero todo ese rollo de andar mirando la variable frames me parece un poco rebuscado.
Re: SYNCronizar velocidad juego (variable FRAMES)
El problema es si "tu rollo" no se puede hacer en ese 50avo de segundo. Lo cual parece ser el caso.
Re: SYNCronizar velocidad juego (variable FRAMES)
jsj escribió:El problema es si "tu rollo" no se puede hacer en ese 50avo de segundo. Lo cual parece ser el caso.
Si, perdon que he editado para decir una cosa mientras escribias. Aun si "tu rollo" no cabe en 0,020, un HALT lo sincronizarán a 0,040 (porque una interupcion y una no, se ejecutan durante "tu rollo". Si "tu rollo" dura 0,045 entonces se ejecutará cada 0,060, y así sucesivamente, pero siempre con la mismo cadencia.
En el fondo es lo mismo que estar mirando a ver si la variable frames sube de valor, pero no se, me parece más fino
Y como digo, si es que actualizar cada 0,0020 es demasiado rápido y se hace injugable, pues:
Código: Seleccionar todo
HALT
HALT
HALT
HALT
Re: SYNCronizar velocidad juego (variable FRAMES)
Es que deduzco que el caso es ese. Que "tu rollo" es de duración variable. Por lo que menciona el pintado de pantalla dura más cuantos más "tiles" o "sprites" haya que actualizar. Lógicamente.
Por tanto para obtener cadencia estable hay que medirlo y sincronizarlo de alguna forma.
Sobre usar la variable FRAMES o una rutina de interrupción propia ya no me meto. Mi Z80 está muyyyy oxidado.
Por tanto para obtener cadencia estable hay que medirlo y sincronizarlo de alguna forma.
Sobre usar la variable FRAMES o una rutina de interrupción propia ya no me meto. Mi Z80 está muyyyy oxidado.
- Hark0
- Mensajes: 683
- Registrado: 27 Sep 2015, 00:31
- Ubicación: Cornellà de Llobregat - BCN
- Contactar:
Re: SYNCronizar velocidad juego (variable FRAMES)
Leidos los 4 post... muchas gracias por los aportes.
El tema es el siguiente: estoy acostumbrado a usar rutinas de FPS con SDL2.
Suelo escribir el bucle, calcular los FPS... etc.
Como habeis dicho, si mis calculos, logica etc:
a) terminan antes de tiempo... añado pausas/delays para que se sincronice y espere al siguiente loop.
b) si me quedo sin tiempo... modifico/optimizo mis rutinas para que se sincronice y espere al siguiente loop.
En este caso, tengo los dos problemas a la vez:
Si pongo muchos "objetos" a pintar estoy en el caso B.
Si pongo pocos "objetos" a pintar estoy en el caso A.
En Z88DK se puede meter ASM y de hecho en el "Kit Radastan" ya existe una función para añadir HALTs....
Yo he intentado usar FRAMES, porque me parecia más correcto... y creo que es factible siempre que lo que se vaya a pintar+calcular sea más menos siempre lo mismo...
En este caso, como me gustaría añadir un editor de mapas, estoy a merced de que un usuario le de por meter hasta 176 (mapa de 16x11 tiles) objetos animados en pantalla... y en ese caso... imaginaos.
El tema es el siguiente: estoy acostumbrado a usar rutinas de FPS con SDL2.
Suelo escribir el bucle, calcular los FPS... etc.
Como habeis dicho, si mis calculos, logica etc:
a) terminan antes de tiempo... añado pausas/delays para que se sincronice y espere al siguiente loop.
b) si me quedo sin tiempo... modifico/optimizo mis rutinas para que se sincronice y espere al siguiente loop.
En este caso, tengo los dos problemas a la vez:
Si pongo muchos "objetos" a pintar estoy en el caso B.
Si pongo pocos "objetos" a pintar estoy en el caso A.
En Z88DK se puede meter ASM y de hecho en el "Kit Radastan" ya existe una función para añadir HALTs....
Yo he intentado usar FRAMES, porque me parecia más correcto... y creo que es factible siempre que lo que se vaya a pintar+calcular sea más menos siempre lo mismo...
En este caso, como me gustaría añadir un editor de mapas, estoy a merced de que un usuario le de por meter hasta 176 (mapa de 16x11 tiles) objetos animados en pantalla... y en ese caso... imaginaos.
http://www.zxuno.com
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.
ZX-Uno · Clon de ordenador ZX Spectrum basado en FPGA.