Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Problemas de tiempo, mi juego va a empujones...X(

Iniciado por trutoman, 29 de Abril de 2008, 01:52:42 PM

« anterior - próximo »

trutoman

Hola a todos,

Mi problema es el siguiente, he creado unas clases para manejar sprites y otras para manejar eventos del teclado, hasta aqui todo bien, dado que considero terminada la primera parte de mi mini proyecto. Asi que me he puesto a cronometrar tiempos para ver como va el tema y...

Mi bucle principal de momento solo dibuja y maneja dos sprites con sus animaciones , los eventos de teclado para manejarlos y un fondo de pantalla, q de momento se dibuja entero a cada iteraccion. Pues de media tarda 60 milisegundos en completar una vuelta !!!

Desearia que me dijerais que en el fondo las operaciones graficas son las que mas tiempo consumen, porque ahora deberia implementar:

-El detector de colisiones, con multirectangulos.
-La IA, que tengo pensada con maquinas de estados y unos pocos arbolillos.
-El subsitema de sonido....

Tras implementar esto imagino que mi bucle se ira facilmente a los 100-150 milisegundos no??

Mi pregunta es cual debe ser el tiempo medio por cada iteraccion de un bucle principal en un juego normalillo ?

Porque, si tenemos en cuenta esto de que el ojo humano ve 25 imagenes por segundo, el tiempo optimo del bucle sería 40 ms. Esto seria pedir demasiado?

El hecho de dibujar todo el fondo en vez de solo la parte que cambia pesa mucho en tiempo??

BUeno, gracias anticipadas. TOY HUNDIO

[EX3]

Te iba a responder antes de que desapareciera tu anterior post :P

Deberias realizar las mediciones en cuadros por segundo y no por milisegundos, la idea es llegar a una media de 30 a 60 fps para mostrar un renderizado suave a la vista. Haciendo una prueba rapida en la tostadora que tengo por PC en la oficina, en una prueba con dx_lib32, a 640x480, dibujando el fondo por duplicado (para implementar un efecto) con una textura de 640x480 con TripleBuffer, sin espera de refresco vertical y sin limitacion de fps, 5 sprites con rotaciones (uno de ellos por duplicado tambien para otro efecto implementado), aplicando efectos a las texturas de los sprites y el fondo y dibujar quads con degradados me da una media de 62 fps y una media de 10/5 milisegundos por bucle (la maquina como digo es una autentica tostadora de oficina de hace 4 o 6 años). En casa con el MacBook con una integrada intel 950 y el AMD con la GeForce3 supera los los 90 fps de sobra, por lo que el tiempo de ciclo seguro se rebaja a mucho menos de 3 milisegundos.

Si expones el como estas implementando las llamadas quizas sepamos ayudarte. Me huele a que estas recargando texturas en el propio bucle o realizando algun paso que te puedes ahorrar perfectamente.

CitarDesearia que me dijerais que en el fondo las operaciones graficas son las que mas tiempo consumen, porque ahora deberia implementar:

-El detector de colisiones, con multirectangulos.
-La IA, que tengo pensada con maquinas de estados y unos pocos arbolillos.
-El subsitema de sonido....
De las que has mencionado, las colisiones y la IA, pero claro, dependiendo de como de complejas sean ya que no existe una implementacion unica de estos modulos. El sistema de audio generalmente suele correr siempre en un hilo independiente por lo que no demorara el hilo principal del programa (esto lo gestionan las propias librerias como DirectSound y similares).

CitarTras implementar esto imagino que mi bucle se ira facilmente a los 100-150 milisegundos no??

Mi pregunta es cual debe ser el tiempo medio por cada iteraccion de un bucle principal en un juego normalillo ?
Centrate en que el programa mantenga una media de 30 a 60 fps, no busques un tiempo fijo en milisegundos por esto varia segun la carga de datos a procesar en el bucle.

Lo principal que debes tener en cuenta a la hora de optimizar los modulos es intentar evitar llamadas en los momentos que no sean necesarios, por ejemplo dibujar sprites fuera de pantalla (descarta todo lo que no sea visible) o calcular toda la fisica de golpe (esto cuando profundices un poco veras que se divide la escena de forma que calcules solo lo necesario). La IA ya es mas compleja de optimizar pero igualmente hay formas de agilizarla, segun veo se esta poniendo de moda el procesar la IA entre otras cosas en un hilo independiente al principal, pero claro, segun casos, en un PacMan no te merece la pena mientras que en un Quake quizas si.

Ve por partes. Yo no me comeria la cabeza con colisiones y maquinas de estados hasta no tener asegurado el modulo grafico.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

trutoman

JAjaj , te has dado cuenta.

Este foro es mortal o te publica por duplicado o no te publica.

Agradezco tu respuesta fuenlabreño.

A que te refieres exactamente con frames?, se que es una pregunta tonta pero esque tiene tantas acepciones.
A las veces que llamo a mi funcion Pantalla.Actualizar? esta funcion blitea a la pantalla lo que hay en memoria de video, digamos, se que sabes lo q quiero decir, primero hago todas las animaciones los cambios de posicion y luego llamo a Pantalla.Actualizar que lo blitea todo a pantalla. Cuando hablas de frame te refieres a las veces que flasheo la pantalla?

Si es asi, no llego a 30 por segundo ni de coña. Cuando este en casa lo mido y t lo digo.

Antes se me olvidó dar un dato muy importante que me has recordado al hablar de la tostadora de tu oficina, mi programa de momento esta corriendo en mi ordenador personal, y le llamo personal porque hace tanto tiempo que lo tengo que ya le he cogido cariño....

PIII 800, XDDD en su defensa he de decir que la grafica es una Geforce4MX4000, tiene 1 Gb de memoria y El gestor de escritorio de Ubuntu, BERYL realiza todos los efectos a la perfeccion, por no hablar del Warcraft III que puede correr con todas las opciones graficas al maximo con una suavidad q ya la querrian muchos PIV XDD.

En las pruebas que estoy haciendo todo es optimo, dibujo los sprites justos y lo unico que podria mejorar  es dibujar solo la parte del fondo que cambia y no todo como hago ahora.

Loover

Mierda, escribí un post en el otro hilo que hiciste pero lo han debido borrar, seguramente lo eliminaron justo después de haber publicado yo y no lo vieron.

Uuuuf q pereza volver a escribir, bueno no pasa na.

Ahí va otra vez:

1) Mide en frames por segundo mejor, es decir, número de veces que presentas en pantalla todos los gráficos en un segundo.
2) Si usas SDL y quieres que el dibujado vaya más rápido, tendrás q meterte con mierdas de dirty rectangles, etc, es decir, dibujar solo las zonas que cambian. Si usaras aceleración por hardware podrías olvidarte de eso y ganar mucha velocidad.
3) Los fps de tu juego, visto el tipo de juego que es, no se te van a ir en la lógica o las colisiones, ahí como mucho se te irán 2 o 3 fps. Tu cuello de botella por frame, como casi siempre, es dibujar todo, y más si es por bliteado por software como es tu caso.
4) Vigila que no estés haciendo alguna burrada, como hacer new/delete en cada iteración del bucle o algún "sleep" olvidado por ahí.
5) Yo no he usado SDL directamente nunca, pero indirectamente, usando Fenix (que usa SDL internamente), los juegos me iban a 30 o 40 fps en un pentium 200Mhz.
6) Ahora mismo, con la IndieLib y aceleración por hardware... bueno, prueba tu mismo los ejemplos, puedes tener 2000 sprites en pantalla rotándose, escalándose y cambiando su entintado a unos 30fps más o menos. Y un escenario con un fondo y tan solo 3 sprites, a 1024x768, en un ordenador de gama media, no debería bajar de los 300fps (con aceleración hardware). Depende, claro del tamaño de los sprites.
7) Si tienes bien separada la lógica del juego de la de dibujado, siempre puedes terminarlo ahora dibujando por fuerza bruta (sin usar dirty rectangles) y más tarde usar Direct3d, Ogl a pelo, o alguna api de dibujado de más alto nivel, para ganar velocidad. Pero entonces deberías tener cuidado y crear solo sprites potencia de dos (o más tarde usar un engine que te permita usar sprites que no sean potencia de dos).
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

synchrnzr

Perdón por la confusión de los posts desaparecidos, es que justo ha publicado [EX3] la repuesta al duplicado que estaba eliminando :(

sync

[EX3]

Ale ale, tan pronto desaparecen mensajes como de pronto posteamos todos a la vez :D Este foro es unico :lol:

Cita de: "trutoman"A que te refieres exactamente con frames?, se que es una pregunta tonta pero esque tiene tantas acepciones.
A las veces que llamo a mi funcion Pantalla.Actualizar? esta funcion blitea a la pantalla lo que hay en memoria de video, digamos, se que sabes lo q quiero decir, primero hago todas las animaciones los cambios de posicion y luego llamo a Pantalla.Actualizar que lo blitea todo a pantalla. Cuando hablas de frame te refieres a las veces que flasheo la pantalla?
Caliente caliente, tambien engloba calculos de fisica e IA. En verdad, para ser mas concretos, seria el numero de vueltas que ejecutas el bucle principal en un segundo. La tasa optima suele ser 60 veces pero hasta 30 la frecuencia es aceptable. Por eso te decia que no midas en milisegundos ya que nunca obtendras un valor fijo debido a las variantes de procesos. Mide solo en milisegundos para testear individualmente una funcion concreta para depurar posibles demoras localizadas en tu codigo.

No estoy puesto para nada en SDL pero se que han comentado alguna vez que las conversiones de tipo de pixel (entre superficies por ejemplo) puede bajar notoriamente el rendimiento. Recuerda que SDL ejecuta por software y no por hardware como si lo hace OpenGL y Direct3D.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

trutoman

Vaya esto se complica, no tenia ni idea que opengl iba directo al hardware, para q veais la idea que tengo XD...
Ahora mismo mido los fps.
Buena idea esa de medir cada funcion por separado para ir optimizando las mas lentas, me pongo a ello.
He depurado un poco y no hago nada raro;
*Cargo sprite
*Lo bliteo en la surface temporal
*Lo elimino
*Y cuando todos los sprites estan dibujados, flasheo a la pantalla fisica.
Lo habitual imagino...

trutoman

No puede ser!!

Hago lo siguiente:

Inicializo todo, sprites, pantalla, animaciones.

while (!fin)
    uint32 start = 0
    Dibujarsprite(1)
    Dibujarsprite(2)
    Animar(1)
    Animar(2)
    start = sdl_getticks
    if (start>1000)
        fin = true
   
Pues bien, da una vuelta y tarda 3700 milisegundos????
Si pongo el limite a 10000, por si me equivoco con las unidades de medida, aunque pensaba que daba milisegundos da 111 vueltas

[EX3]

Cita de: "trutoman"He depurado un poco y no hago nada raro;
*Cargo sprite
*Lo bliteo en la surface temporal
*Lo elimino
*Y cuando todos los sprites estan dibujados, flasheo a la pantalla fisica.
Lo habitual imagino...
Error como una catedral! Los recursos como las texturas se cargan al principio o antes de la escena y se mantienen en memoria hasta la finalizacion del programa o hasta que tengas que cargar, por ejemplo, un nuevo nivel. Cargar desde disco, crear y eliminar en memoria es un proceso muy muy costoso. No te obsesiones con lo que ocuparas en memoria cargando todas las texturas ni resto de recrusos, que no estamos hablando de programar un Spectrum 48k :D Lo que se suele hacer es tener un "pool" de recursos (como un almacen mas o menos organizado segun necesidad) por ejemplo, un array/coleccion/lista donde almacenas las texturas que necesitas y a donde accederas para leerlas. Esto es mil veces mas rapido ya que estas leyendo en la RAM o en la memoria de la grafica, mas rapido que acceder a disco.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

trutoman

Tienes razon, pero la verdad es que me he explicado mal.

Yo cargo el fichero de imagen  entero y creo unos vectores con las coordenadas para hacer  los recortes de todos los sprites.
Esto antes de empezar el bucle de juego.
Luego la funcion dibujarsprite simplemente coge del vector de coordenadas las que le toquen y corta del fichero la imagen adecuada.
Ambos vector de coordenadas y fichero de imagen estan en memoria.
Se que un acceso a disco es del orden de 100000 mas lento que un acceso a memoria;
se puede hacer mas rapido?

[EX3]

Por carga de sprite te referias pues a seleccionar la superficie a dibujar y su region definida. Hasta ahi bien supongo. Lo costoso seria realizar duplicados de texturas en tiempo de ejecucion y demas historias semejantes.

Sobre el calculo de fps, el primer ciclo del bucle no siempre es el mas fiable, realmente deberias tener en cuenta la media que te durante la ejecucion. Para realizar el calculo deberias hacer algo como esto:

int last, framesDrawn;
int frameRate; // Este es valor que representa los cuadros por segundo.
if(sdl_GetTick() - last >= 1000)
{
   last = sdl_GetTick();
   frameRate = framesDrawn
   framesDrawn = 0
}

Esto lo ejecutas justo de despues de pintar la escena, al final de bucle. Con esto obtendras la cuenta fiable de cuadros por segundo.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Loover

Citar
Yo cargo el fichero de imagen entero y creo unos vectores con las coordenadas para hacer los recortes de todos los sprites.
Esto antes de empezar el bucle de juego.
Luego la funcion dibujarsprite simplemente coge del vector de coordenadas las que le toquen y corta del fichero la imagen adecuada.
Ambos vector de coordenadas y fichero de imagen estan en memoria.
Se que un acceso a disco es del orden de 100000 mas lento que un acceso a memoria;
se puede hacer mas rapido?

A ver si me queda claro.

Cuando accedes a la imagen en memoria no accedes a disco, solo lo haces una vez al cargar, eso está bien.

Al dibujar, bliteas (dibujas) una región en concreto de la imagen grande. Eso está bien.

Lo que estaría mal es si para dibujar dicha region, la recortas y la pegas en otra dirección de memoria tuya, eso estaría muy muy mal :D El único copiado de dicha región debe hacerse al buffer de dibujo, y en este caso SDL se ocupará de eso con su función pertinente de bliteado.

Mira a ver si haces algo de esto dentro del bucle principal del juego (olvidate de la parte en la que cargas y la parte en la que liberas memoria fuera de dicho bucle):
¿Haces algún new/delete?
¿Haces algún copiado/pegado de memoria?
¿Haces algún acceso a disco?

Si la respuesta es sí a alguna de esas, pues ya tendrás algo que podrás evitar y ganar muchos fps.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

trutoman

Bueno ya he conseguido medir las fps, y no paso el corte, lo he hecho mil y una veces y no paso de -17- siempre 17 vueltas da en un segundo.

En cuanto a las preguntas de loover si, tienes razon, cargo la imagen en memoria, y luego interiormente la clase CSprite copia su parte de la imagen a una surface suya que hace de buffer, y de ahi cuando sea requerido lo copia a memoria., es decir hago una copia intermedia que me puedo quitar.

Si no he entendido mal te refieres a pasar del fichero cargado en memoria directamente a pantalla el sprite adecuado verdad.

Ahora hare ese cambio a ver si me llega a 30 fps.

[EX3]

Citarla imagen en memoria, y luego interiormente la clase CSprite copia su parte de la imagen a una surface suya que hace de buffer, y de ahi cuando sea requerido lo copia a memoria., es decir hago una copia intermedia que me puedo quitar.

Si no he entendido mal te refieres a pasar del fichero cargado en memoria directamente a pantalla el sprite adecuado verdad.
En memoria lo que debes evitar es crear superifcies en tiempo de ejecucion. Doy por hecho que SDL tendra una funcion para seleccionar una superficie para realizar las operaciones de dibujo y que esta funcion tendra sus parametros para poder definir que region de la superficie dibujar, llamemosla SDL_SetSurface(). Tu tendrias tus imagenes almacenadas como superficies en una lista cuando las cargas desde disco al cargar la escena y esas seran las unicas superficies que tendras a parte del backbuffer, por ende tus llamadas al bucle quedarian similar a estoi:

SDL_Rect region;

Do While (fin)
{
   region.x = 0; region.y = 0; region.width = arrSuperficies[0].width; region.height = arrSuperficies[0].height;
   SDL_SetSurface(arrSuperficies[0], region);
   SDL_Blit(0, 0, 32, 32);

   region.x = 32; region.y = 32; region.width = 32; region.height = 32;
   SDL_SetSurface(arrSuperficies[1], region);
   SDL_Blit(128, 64, 32, 32);

   SDL_Flip();
}

Esta al menos seria la forma de hacerlo en Direct3D. Ahi no realizas ninguna copia ni generas nuevas instancias de objetos lo que te ahorra carga al procesador y por ende ganas velocidad. Ten siempre en cuenta que la carga y creacion de texturas y superficies es un proceso costoso, y mas por software por lo que debes evitarlas. Leer de la memoria siempre sera mas rapido que copiarla a otra seccion y leerla despues.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

trutoman

Pues si asi lo voy a hacer.

He medido el tiempo individual de cada funcion.
El dibujar los dos sprite me da 0 ó 1 milisegundos, mientras que dibujar el fondo de pantalla consume 40 milisegundos, si cogemos que doy 17 vueltas, 17*40 = 680, es decir el 68% del tiempo lo gasto en pintar el fondo, esto me lleva a una conclusion obvia -> DirtyRectangles.
Estoy pensando como hacerlo y el problema primero que me ha llamado la atencion es que antes de dibujar cualquier cosa tengo que conocer las coordenadas de todo lo que he dibujado en la iteraccion anterior...OMG creo que abrire otro post para esto XDD. Perdón, antes me documentare y si no me sale bien a la primera entonces abrire post.

Probando el programa de prueba sin pintar el fondo me daba 58 fps. Thats GOOD






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.