Optimizando los tiles

Started by Drumpi, August 15, 2011, 10:45:07 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Drumpi

Hola a todos:

Como sabeis, me encuentro un poco vago, y con pocas ganas de experimentar, así que me gustaría recurrir a vuestra experiencia antes de dar un paso en una dirección  ;D.
Mi motor de tiles más o menos es óptimo, pero el que haya probado el Echo en WIZ o GP2X habrá notado unas ralentizaciones algo molestas (aun con overclock), así que tengo que mejorarlo. Parte de la culpa de estas bajadas de frames se deben a los enemigos, pero ya estoy dándole vueltas para solucionarlo.

Se me han planteado dos formas de optimizarlo:
-Reducir el número de procesos tile: juntar dos o cuatro tiles iguales y crear bloques, de forma que puedo agrupar dos o cuatro procesos en uno sólo, usando un tile más grande. En algunos niveles se podría reducir la carga de procesos a la mitad.
-Cambiar el motor por otro de dibujado en mapa: la idea sería tener un mapa del tamaño de la pantalla y dibujar los tiles sobre él, de forma similar a como lo hacía en Thunder Blade. Tal como lo tengo planteado, necesitaría un scroll, y por cada tile que se avanzase se redibujaría una zona de 16x240 o 320x16 pixels (incluso menos). Sé que las herramientas PUT son lentas, pero con tan poco a dibujar creo que la carga sería mínima.

La cosa es que no sé qué método me garantizaría más velocidad, y como dentro de poco se me acaban las vacaciones sólo puedo probar con uno ¿qué os dice vuestra experiencia? ¿se puede dibujar ese espacio a suficiente velocidad o modifico los mapas de tiles? (obviamente, no puedo aplicar ambos métodos a la vez).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

l1nk3rn3l

vi este doc en el bennupack que puede servir para los enemigos...

sobre los tiles, creo que put es rapido... aunque no lo he probado
en hardware limitado como la gp2x y demas



****************************************************************************
                PROCESO PARA Fenix "pon_monedas"
****************************************************************************

Uno de las fallos que muchos programadores tienen a la hora de hacer un
juego tipo Plataformas es la cantidad de memoria y procesador que requieren
estos. Esto se debe a que una vez que se crea una fase, si esta tiene 800
monedas por ejemplo y 500 enemigos, todos cargados a la vez, aunque no esten
en pantalla, estan gastando furiosamente memoria. Mi proceso evita este
problema, haciendo que a menudo que el personaje se vaya moviendo, las monedas
y demas objetos van apareciendo, osea, se crean un poco antes de que vayan a
aparecer, y cuando los dejamos atras, mueren. Ademas, si nuestro personaje
eliminara alguno de esos procesos, ya sea recogiendo monedas o matando a los
enemigos, dicho proceso ya no aparecera mas (como debe ser, claro).

Antes de ver el proceso hay que saber lo siguiente:

- Las monedas (o bichos, u objetos, o lo que sea) a crear ya no se crearan
  como antes, simplemente hay que llamar una sola vez al proceso pon_monedas.

- En GLOBAL del programa hay que definir dos matrices:

  A) viva[Nro de monedas];       (Para indicar si cada moneda esta viva 1
                                o muerta 0)
  B) id_coin[Nro de monedas];    (Indentificador de cada moneda)

  Donde "Nro de monedas" es el numero de monedas maximo que pueda aparecer
  en cualquier fase del juego

  Ejm. viva[300];
       id_coin[300];

- En LOCAL del programa hay que definir la siguiente variable:
  Numero;    (Que sera el numero de cada moneda)

Ahora pasamos a ver el proceso suponiendo que el juego esta a una resolucion
de 320x240, las monedas han sido llamadas "coin", el personaje que las debe
recoger es "personaje", y tenemos por ejemplo, 200 monedas como maximo.

Ah! Y no hay que olvidar que las monedas no las crearemos poniendo nosotros
las coordenadas, sino colocando puntos de control en el mapa donde apareceran
dichas monedas. El proceso se encargara de quitarlas o ponerlas cuando le
corresponda.

// ----------------------------------------------------------------------
// PROCESO PARA PONER MONEDAS (ENEMIGOS, OBJETOS...) CUANDO SEA NECESARIO
// ----------------------------------------------------------------------

PROCESS pon_monedas();     // Puede ser "pon_monedas", "pon_bichos"... :)

PRIVATE

numero_de_moneda[200];     // Una tabla que indica si cada moneda esta puesta o no
contador;                  // Contador de las monedas a crear-matar-modificar

BEGIN

FROM contador=1 TO 200;                         // Este bucle crea TODAS las monedas
    get_point(0,1,contador,&x,&y);              // Obtiene las coordenadas de los puntos de control de un supuesto mapa nro 1
    IF (x<>0 AND y<>0)                          // Cuando las coordenadas son 0 quiere decir que no hay mas monedas
        id_coin[contador]=coin(x,y,contador);   // Crea la moneda con las coordenadas y su numero correspondiente
        numero_de_moneda[contador]=1;           // Se indica que dicha moneda esta puesta (1)
        viva[contador]=1;                       // Se indica que dicha moneda esta viva (1)
    END
END

LOOP                                        // Este bucle permanecera durante toda la fase

    FROM contador=1 TO 200;                 // Este bucle estudiara cada moneda
        get_point(1,1,contador,&x,&y);      // Obtiene las coordenadas de cada moneda (los puntos de control del mapa)

        // A continuacion se hacen dos comprobaciones, la primera consiste
        // en averiguar si una moneda que no esta en pantalla y que sigue
        // viva, esta lista para ser puesta, y en la segunda comprobacion
        // se averigua si una moneda que esta viva y puesta debe ser quitada
        // de pantalla para ahorrar memoria.

        // 1ro Si en las coordenadas hay o habia moneda y se encuentra cerca del personaje y no esta puesta en escena,
           pero esta viva
        IF (x<>0 AND y<>0 AND x<id_personaje.x+320 AND x>id_personaje.x-320 AND
            y<id_personaje.y+240 AND y>id_personaje.y-240 AND numero_de_moneda[contador]==0  AND viva[contador]==1)

            // Creamos dicha moneda
            id_coin[contador]=coin(x,y,contador);
            // Y ahora indicamos que esta puesta
            numero_de_moneda[contador]=1;
        END

        // 2do Si en las coordenadas hay o habia moneda y se encuentra lejos del personaje y esta puesta en escena y viva
        IF (x<>0 AND y<>0 AND (x>id_personaje.x+320 OR x<id_personaje.x-320 OR y>id_personaje.y+240 OR
            y<id_personaje.y-240) AND numero_de_moneda[contador]==1 AND viva[contador]==1)

            // Quitamos la moneda para ahorrar memoria
            signal(id_coin[contador],s_kill);
            // E indicamos que no esta puesta (aunque si viva)
            numero_de_moneda[contador]=0;
        END

    END

    FRAME;
END

END

// ---
// FIN
// ---

Ademas de todo esto, hay que tener en cuenta que cuando el personaje toque
una moneda, esta de morir definitivamente, cambiando su variable "viva" a 0.
Deberiamos incluir en el proceso del personaje algo como esto:

    IF (id2=collision(TYPE coin))   // Si toca una moneda
        viva[id2.numero]=0;         // le quita la vida
        signal(id2,s_kill);         // y la quita de pantalla
    END

****************************************************************************
                (C) Francisco Bermudez Carvajal 1996/1999                                               
****************************************************************************

Drumpi

#2
Gracias, Link, esto creo haberlo leido en el manual de div. De todas formas, gracias al mapa de tiles esto lo puedo hacer de una manera más sencilla.

Al final he decidido perder la mañana y realizar una prueba preliminar. He cogido la GP2X y le he metido el test del scroll tileado con el mapa del segundo nivel del Echo (es el que más tiles tiene), y por otro lado una versión super-rápida, y super reducida (y super llena de bugs, porque no borra tiles) de un motor que pinta tiles en un mapa.

El scroll tileado actual ronda los 60FPS (330FPS si no hay movimiento del scroll, y 90 si hay poca carga de tiles) y baja a 38 en cuanto se llena la pantalla de tiles (por lo general no baja de 45).
El "scroll" por pintado empieza a 96FPS, pero en cuanto ha pintado todo el mapa baja a 89FPS (supongo que será cosa del dump y restore, que los tengo por defecto). Lo bueno es que no baja de ahí en ningún momento... Quizás cuando le digo que vaya hacia atrás, que baja a 74, pero ese movimiento lo tengo mal hecho: no comprueba el cambio de tile, ejecuta el refresco de columna a cada frame (y no sé ni dónde está pintando, sólo se que pinta una columna de 16x304 pixels como máximo).

Todo esto en GP2X, sin overclock (o sea, a 200MHz) y sin RAM Timings.
O sea, que parece ser que me toca crear una nueva versión del motor graph_tscroll. Eso me va a llevar tiempo (con el anterior y con el de TH me llevaron como un mes).

EDIT:120-100 FPS la versión dibujada haciendo overclock a 240MHz y con RAM Timings, todo esto en Open2X
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

KeoH

pos no se .. pero si corriges los bugs esta de puta madre xD porq mas de 24fps no vas a ver xDD te da igual q el framerate minimo sea 38 xD

Futu-block

yo no entiendo mucho de fps y to ese royo, pero intentalo hacerlo por capas, un tile vasico monocolor que haga de fondo y otro semi transparente que haga de terminacion, igual hace falta menos tiles y con convinaciones de tiles salen nuevos...

que igual lo carga mucho, no se...

Drumpi

Keoh: en realidad sí que se ven. La percepción humana necesita de 34 imágenes por segundo para detectar movimiento, es la teoría, pero si ves animes japoneses, en su mayoría no tienen más de 10 imágenes por segundo (y lo sé porque he visto y creado gif animados de los mismos), pero sí que hay diferencia entre 40 y 50 imágenes por segundo, y los ojos más entrenados incluso notan la diferencia con 60, sobre todo, en la suavidad.

Pero aquí lo importante no es la suavidad, sino que los FPS determinan la velocidad del juego, y si el juego está definido para ir a 50FPS, si va a menos se nota ralentizado. Es un efecto que habrás visto más de una vez en emuladores, en juegos de PC que van justitos o en algunos juegos de consola cuando la pantalla se llena de acción.

Hacer pruebas poniendo SET_FPS(0,0) sirve para ver a qué velocidad puede mover el HW el programa que estás haciendo. Cuando mayor sea, mejor, porque irá más desahogado (tendrá tiempo para realizar otras tareas en segundo plano o te prmite añadir más cosas).
En máquinas con recursos tan limitados como GP2X o WIZ, es un indicativo de si podrá moverlos o no: en este caso, el juego va a 50FPS, con el actual motor casi lo podría mover, salvo cuando se llena de tiles (que va por debajo de 50FPS), pero si pongo el nuevo, que va a 90FPS sí podría funcionar... siempre que el resto del código no gaste más de los 39FPS sobrantes.

Futu: creo que no funcionaría, lo que se trata es de reducir el número de procesos tile, o bien crear el nuevo motor intentando que no dibuje más de media pantalla. Por suerte, el movimiento del personaje no es muy rápido y sólo redibujaría una fila o una columna cada 16 frames (o cada 8, no recuerdo si iba a 1 o 2 pixels por frame). El problema sería con scrolles bruscos o cambios de localización.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)