Temporización en Allegro

Temas relacionados con la programación y la actualización audiovisual
User avatar
benway
Usuario avanzado
Posts: 172
Joined: Sun Apr 03, 2005 1:22 pm
Location: Madrid

Temporización en Allegro

Postby benway » Thu May 05, 2005 10:55 am

Bueno, como es el primer mensaje que escribo en el foro... pues ante todo presentarme. Me llamo Luis, y soy quien hizo la versión del Columns (Panik software) que se publicó en esta web hace un par de meses.

Quería consultaros una cosilla. Estoy metido de lleno en un nuevo proyecto (me queda muy poquito de código, y mucho de gráficos :? ): Como es mi segundo programa, es algo sencillito... un remake del "Horacio Esquiador" que, a buen seguro, todos vosotros conoceréis.

El caso es que me ha surgido un problemilla: Necesito hacer un retardo en el ciclo principal del juego, para que vaya a una velocidad jugable e igual entre distintos ordenadores. El caso es que el retardo debería ser de unos 6 ó 7 mseg... y... tras implementarlo... ¡a veces funciona y a veces no! He estado probando, y he descubierto que no me funcionan los retardos inferiores a 16 mseg, pq, ya os digo, según le de, los hace de 16 mseg igual, aunque sean de menos. Lo cachondo del caso, y vuelvo a insistir, es que a veces funciona y a veces no :shock:

Por cierto, que uso Dev-C++ 4.9.9.2 y la última versión de Allegro, la 4.2 Beta 2 (pero he probado con otras versiones, como la 4.0 y nada...).

Os agradecería encarecidamente cualquier tipo de ayuda y / o sugerencia :)

Para que veáis a qué me refiero, os pongo aquí un código de ejemplo, lo más simple que he podido (Tras ejecutarlo, ya os digo, a veces me pone que no funciona y otras veces que sí que funciona :? ):

#include <allegro.h>

volatile unsigned int Contador;

void tempus () {
Contador++;
}

END_OF_FUNCTION(tempus)

void init();
void deinit();

int main() {
init();

while (!key[KEY_ESC]) {
textprintf_ex (screen,font,20,20,makecol(255,255,255),0," %i ",Contador);
Contador = 0;
while (Contador<6);
if (Contador>14) textout_ex (screen,font,"NO FUNCIONA BIEN",20,28,makecol(255,255,255),0);
else
textout_ex (screen,font,"Si que funciona",20,28,makecol(255,255,255),0);
}

deinit();
return 0;
}
END_OF_MAIN();

void init() {
int depth, res;
allegro_init();
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
if (res != 0) {
allegro_message(allegro_error);
exit(-1);
}

install_timer();
install_keyboard();
install_mouse();

LOCK_VARIABLE (Contador);
LOCK_FUNCTION(tempus);
install_int_ex(tempus, MSEC_TO_TIMER(1));
}

void deinit() {
clear_keybuf();
remove_int (tempus);
}
Un saludo.Image - Image
User avatar
pauvictor
Usuario habitual
Posts: 13
Joined: Sat Oct 30, 2004 8:53 am
Location: Valencia

Postby pauvictor » Thu May 05, 2005 4:45 pm

Hola.

No entiendo mucho de allegro, y imagino que estaras programando bajo windows. Si es asi, ten en cuenta que con las funciones de retardo que da el API de windows que deben ser las que usa Allegro de igual forma que lo hace SDL, no se puede esperar que un plazo (retardo) se cumpla si es menor del quantum del planificador del SO. Si no me equivoco, en windows este quantum es de 10mseg, al igual que el de linux.

Esto simplemente quiere decir que si tu sueltas la CPU y alguien la coge, puede quedarsela 10 mseg sin problemas, ya que son los que le da el windows... Si esto te supone un problema, una alternativa para el juego puede ser hacer esperas activas. No son elegantes, ni optimas pero como en esencia un juego se ejecuta el primer plano en el sistema y toma todos los recursos no deberia suponer un gran problema.

Si en allegro se puede hacer de alguna forma con una precision menos de 10 lo desconozco. Yo solo se que estas cosas son las que me contaron el año pasado en clases de Sistemas Operativos....

Adios.
User avatar
Popolon
Usuario avanzado
Posts: 474
Joined: Tue May 13, 2003 2:31 pm
Location: Lloret de Mar
Contact:

Postby Popolon » Thu May 05, 2005 6:44 pm

exacto, el problema es exactamente el que dice pauvictor.

Pero aún y así, la precisión de las rutinas de espera nunca será de menos de 10-15msegundos (ahora mismo no recuerdo de exactamente cuanto).

De todas maneras, para esperar un cierto número de milisegundos te estas complicando la vida mucho.

En windows podrías usar direcamente esta función ("GetTickCount" retorna el nº de milisegundos que ha pasado desde que encendiste el ordenador):

void pause(int msec)
{
long t1=GetTickCount();
while(GetTickCount()-t1)<msec);
}

Pero eso solo compilaría en windows, si usas SDL, puedes usar la función SDL_GetTicks() en lugar del GetTickCount, y seguro que en Allegro hay alguna función parecida.

Pero yo creo que utilizar retrasos _NO_ es la mejor manera de hacer que un juego vaya igual de rápido en todas las máquinas (ya que el retraso necesario dependerá de cada máquina)), lo mejor sería que hiciese algo así:

imagina que quieres que tu juego funcione a 50 frames por segundo, habría que hacer esto: (como 1000 / 50 = 20, hay que dibujar un frame cada 20 milisegundos)

long t1=GetTickCount();
while(!end_of_game) {

// aquí deberías mirar la cola de eventos, para que windows o Linux no digan
// que "la aplicación no responde"
// ...

if (GetTickCount()-t1>20) {
// realizar un ciclo del juego
// ...
t1+=20;
}
}

con eso te aseguras de que se ejecuten exactamente 50 ciclos del juego por segundo sea la máquina que sea.
Guest

Postby Guest » Thu May 05, 2005 8:15 pm

MUCHISIMAS GRACIAS A LOS DOS.

La verdad es que me olía yo que tenía que ser algo así, porque un mismo ejecutable, sin volver a recompilarlo, iba rápido o lento segun le diese :?

Popolon, en Allegro el manejo de la "temporización" (por lo menos, según la ayuda del propio Allegro), solo se puede hacer o con la función rest(int msec), que espera los msec que le digas, o "instalando" temporizadores, que lo que hace es que manda al programa a ejecutar una función a parte cada x tiempo. Yo uso install_int_ex, que el x tiempo se lo dices en ticks de reloj (dice la ayuda que hay 1193181 por segundo).

El procedimiento que uso en el ciclo del juego es el siguiente:

.- Cada msec, (1193 ticks), ejecuta la funcion "tempus", que lo que hace es incrementar la variable Contador
.- El ciclo ppal comienza con Contador = 0
.- Al final del ciclo hay una instrucción while (Contador < PAUSA_QUE_YO_QUIERO);

Supongo que esto es análogo a lo que me comentas, y el problema es que el Allegro, por lo que comentáis, se pierde un poco con los ticks cuando quieres que los detecte tan "rápido".

A lo mejor es que la manera de hacerlo no es correcta... tengo que probar a hacerlo de esta otra manera: Encerrando todo el ciclo en un IF: if (Contador >= PAUSA_QUE_YO_QUIERO) { ... }, que sería la traducción a Allegro de lo que me propones (supongo)

Como nota curiosa, he notado que ese "retardo" que se "auto-genera" es más frecuente en los primeros minutos tras encender el ordenador (En mi casa, porque en el trabajo es raro que no se "genere" y que corra "rápido", aunque tb pasa a veces).

Bueno, disculpad por todo el rollo que he soltao, y espero haber entendido lo que me queríais decir... pq todavía me hago mucho lío con esto de la programación: En Noviembre del 2004 empecé a leer un pdf que se llama "Aprenda ANSI C como si estuviese en primero", y... aquí estamos 6 meses más tarde... :?

Y... para terminar... otra vez MUCHAS GRACIAS por vuestra pronta respuesta :) :) :)
User avatar
benway
Usuario avanzado
Posts: 172
Joined: Sun Apr 03, 2005 1:22 pm
Location: Madrid

Postby benway » Thu May 05, 2005 10:24 pm

He hecho una solución un poco cutre, pero a ver qué os parece...

Primero he creado un temporizador que aumenta una variable cada segundo. Otra variable, que vale cero, se aumenta mientras el temporizador valga 0, es decir:

Variable TEMP aumenta cada segundo.

Temp = 0;
Retardo = 0;
while (!Temp) Retardo++;

y luego quito el temporizador.

Luego, para retardar el ciclo, pongo

for (n=0; n<PAUSA_QUE_QUIERO * (Retardo/1000); n++);

es decir, que se que tarda 1 segundo en "contar" desde 0 hasta x, luego en un milisegundo "contara" hasta x / 1000. Hago un bucle vacío que "cuente" los milisegundos que quiero y ya está.

En teoría debería ir igual de rápido en todos los ordenadores.

¿Qué os parece? ¿Demasiado cutre? :?
Un saludo.Image - Image
Guest

Postby Guest » Fri May 06, 2005 3:52 pm

Hola, a mí también me han traído mas de un quebradero de cabeza lo de los temporizadores, te pongo un ejemplo de código de cómo lo hago yo:

Code: Select all

#include <allegro.h> volatile int target_cycle; void target_incrementor(void); int main(void) { int acycle=0; int x,y; char up,left; BITMAP *buffer; allegro_init(); install_timer(); install_keyboard(); set_color_depth(8); set_gfx_mode(GFX_AUTODETECT,640,480,0,0); buffer=create_bitmap(640,480); target_cycle=0; LOCK_VARIABLE(target_cycle); LOCK_FUNCTION(target_incrementor); install_int_ex(target_incrementor,BPS_TO_TIMER(20)); x=rand()%SCREEN_W; y=rand()%SCREEN_H; up=0; left=0; while(!key[KEY_ESC]) { while(acycle<target_cycle) { /* Hacer aquí la lógica del programa */ if (up) y-=5; else y+=5; if (left) x-=5; else x+=5; if (y>=SCREEN_H) up=1; if (y<=0) up=0; if (x>=SCREEN_W) left=1; if (x<=0) left=0; } /* Dibujar */ clear_to_color(buffer,makecol(0,0,0)); rectfill(buffer,x,y,x+10,y+10,makecol(200,200,200)); vsync(); blit(buffer,screen,0,0,0,0,SCREEN_W, SCREEN_H); } remove_int(target_incrementor); destroy_bitmap(buffer); allegro_exit(); return 0; } END_OF_MAIN(); void target_incrementor(void) { target_cycle++; } END_OF_FUNCTION(target_incrementor);
Eso sí, si el ordenador no es lo suficientemente rápido verás las animaciones como "a saltos".

Mira a ver que tal. :wink:
Guest

Postby Guest » Fri May 06, 2005 4:05 pm

Bueno, soy el de antes, sólo decirte que añadas
acycle++; después de if (x<=0) left=0;

Que fallo, jejeje. :)
User avatar
benway
Usuario avanzado
Posts: 172
Joined: Sun Apr 03, 2005 1:22 pm
Location: Madrid

Postby benway » Fri May 06, 2005 7:01 pm

¡MUCHÍSIMAS GRACIAS!

Ahora sí que va bien. Lo he implementado tal como tú lo has hecho en el ejemplo y va perfecto... mucho mejor que con la cutre-solución que hice ayer.

Lo he probado con el ordenador "nada más reiniciar", que es cuando más lento va, y funciona a las mil maravillas... ¡Qué más se puede pedir! :D :D :D (El finde si voy a casa de mis padres lo probaré allí, que suele ir más lentillo, y el lunes desde el curro... ya te contaré :wink: )

Es que era un poco desesperante tener el programa prácticamente hecho, y que una chorrada como esa impidiera que fuera jugable.
Un saludo.Image - Image
User avatar
benway
Usuario avanzado
Posts: 172
Joined: Sun Apr 03, 2005 1:22 pm
Location: Madrid

Postby benway » Mon May 09, 2005 10:53 pm

Bueno... lo he probado en varios ordenadores distintos, con distintos micros a distintas frecuencias y ... va ¡PERFECTO!

Otra vez... ¡MUCHAS GRACIAS!
Un saludo.Image - Image
Guest

Postby Guest » Tue May 10, 2005 2:38 pm

Pues nada, me alegro de que te sirva, un último consejo:

Si en algún momento sales del bucle principal del programa y haces algo que requiera
muchísimo tiempo o por ejemplo, esperas a que el usuario pulse una tecla, puede que
el programa se 'acelere', para que esto no pase simplemente pon:
acycle=target_cycle=0; justo antes de volver al bucle principal.

Nada más, ¡ánimo y mucha suerte con el remake! :wink:

Return to “Desarrollo”

Who is online

Users browsing this forum: No registered users and 6 guests