7. FPS and UPS
Este es un concepto nuevo, el UPS, que es una manera de medir la velocidad de la animación diferente de FPS, UPS responde a las iniciales de Update Per Second, que significa actualizaciones por segundo, lo que pasa es que el ciclo de animación tiene un update(actualizacion) y un render, pero eso no significa que deba ser así, y lo único que hacemos es actualizar por segunda vez por cada render
public void run() /* actualiza, renderiza y duerme constantemente*/ { /* Reptidamente: actualiza,renderiza, duerme, */ long beforeTime, timeDiff, sleepTime; beforeTime = System.currentTimeMillis(); running = true; while(running) { gameUpdate(); // Actualiza el estado del juego gameUpdate(); // Vuelve a actualizar el estado del juego gameRender(); // renderiza en un buffer paintScreen(); // dibuja el buffer en la pantalla ...
Y ¿que sucede?, bueno imaginemos que tenemos un juego a 50 FPS (50 iteraciones de un ciclo de animación por segundo) haría 100 actualizaciones por segundo, con esto logramos que el juego sea mas veloz, ya que estamos cambiando el estado del juego el doble de rápido, pero obviamente, no podremos renderizar estos estados extra, porque solo renderizara el ultimo estado, aun así esto no se nota mucho, especialmente si el FPS es alto
7.1. Separating Updates from Rendering
Se puede lograr un numero alto de FPS, pero existe un inconveniente, y es la cantidad de tiempo que la actualización y el render necesitan, por ejemplo, 1 segundo tiene 1000 milesimas, entonces para lograr 200 FPS necesitaríamos que el render y actualización no tomen mas de 5ms (1000/5 = 200).
Nota: El render es el que consume mas tiempo.
Ante esta situación, solo queda una forma de incrementar la velocidad del juego, tenemos que aumentar el numero de ups por segundo. En programación esto se traduce en usar la función gameUpdate() mas de una vez. Aun así hacerlo en demasía puede causar la aparación del efecto flicker (parpadeo) en el juego.
La nueva función run() queda así:
public void run() /* actualiza, renderiza y duerme constantemente*/ { /* Reptidamente: actualiza,renderiza, duerme, */ long beforeTime, afterTime, timeDiff, sleepTime; long excess = 0L; beforeTime = System.currentTimeMillis(); running = true; while(running) { gameUpdate(); // Actualiza el estado del juego gameUpdate(); // Vuelve a actualizar el estado del juego gameRender(); // renderiza en un buffer paintScreen(); // dibuja el buffer en la pantalla afterTime = System.currentTimeMillis(); timeDiff = afterTime - beforeTime; sleepTime = period - timeDiff; // timepo que deberia faltar en el bucle if (sleepTime <= 0){ // si actualizar/renderizar toma mas de lo que deberia excess -= sleepTime; // almacenamos el valor de exceso de demora beforeTime = System.currentTimeMillis(); /* Si el frame de animacion toma mucho tiempo, actualiza el estado del juego sin renderizar, en pos de conseguir las actualizaciones x seg necesaria para alcanzar el FPS requerido*/ int skips = 0; while((excess > period) && (skips < MAX_FRAME_SKIPS)) { excess -= period; gameUpdate(); // update state but don't render skips++; } } } System.exit(0); // cierra JFrame o JApplet si existen } // fin de run()
Imaginemos que un actualizado renderizado toma 12ms y se coloca como variable period 10, la variable sleepTime será entonces 2ms, estos 2ms son adheridos a la variable excess que se va sumando por cada vez que pasa el bucle.
Llegara un momento en que excess será mayor a period, en ese momento tiene su razon el ultimo bucle que pusimos, ya que actualizará hasta que excess sea menor a period o se completen las 5 veces que hemos puesto como máximo que se van a actualizar, pero ¿Cual es la razón, motivo, circunstancia de hacer esto? lo que pasa es que cuando excess sobrepasa a period significa que un frame no se renderizo y se perdió.