fpscontrol

#008 ActionScript [Q] Tips: sincronizar FPS

En el útlimo proyecto en el que nos hemos visto embarcados, hemos sufrido muy de cerca 2 características de flash que no son especialmente agradables: no te puedes fiar de los FPS para darle velocidad a un movieclip, y no te puedes fiar de un intervalo, Timer, o como lo quieras llamar para darle velocidad a un clip.

La física ayuda, si un coche va a 40Km/h de forma constante, y avanza recto durante 1 hora, sabes que estará 40 kilómetros desde el punto de medición. Pero en flash lo normal no es actuar así, sino que en un ENTER_FRAME o en un intervalo, le vamos incrementando la posición.
El efecto resultante es que si la ejecución del ENTER_FRAME o del intervalo varía dependiendo del equipo, en cada equipo el coche irá a diferente velocidad. Hasta aquí, siempre que estemos hablando de animaciones de un solo usuario, es un efecto bastante “intrascendente” (lo entrecomillo porque hay casos en los que podría ser perfectamente trascendente), pero por ejemplo en un juego multijugador en el que en el lado del cliente se hace simulación de adversarios y precálculo, la cosa cambia y puede llevar al traste todo el trabajo.

En un mundo perfecto tu tienes que en tu simulación llevas al contrincante por un camino, y cuando sincronizas con el cliente representado por ese elemento, encaja a la perfección, pero ¿qué ocurre si tu oponente tiene un ordenador que no alcanza tus mismos FPS?, que perderá terreno en cada segundo de juego, con lo que al sincronizar, el salto está garantizado… mal rollo.

Después de esta chapa teórica, vamos a la práctica. Si trabajamos con ENTER_FRAME tenemos al alcance una solución sencilla que es “amortiguar” el incremento que queremos darle a una variable (pongamos por ejemplo la posición X) con los FPS reales de la película. Para ello podríamos tomar una de las muchas clases que existen para obtener los FPS “reales” de una película (o la que os dejamos marca de la casa al final del post) y con esos valores trabajar en el ENTER_FRAME tal como se muestra aqui:

x += incremento * (FPS_DESEADOS)/FPS_REALES;

De esta manera se compensa la diferencia entre los FPS deseados y los que la película realmente está ejecutando, de manera que cuantos menos FPS_REALES tenga la película, mayor será el incremento, y por tanto compensará el menor numero de ejecuciones. Si lo “deseado” son 36 fps, y nuestra película va realmente a 18, resultara que tendremos dos veces el incremento, que compensará que efectivamente el enterFrame se ejecute la mitad de las veces.

Si trabajamos con Timer (si, los Timer, setInterval o como se quieran pintar también van como el culo cuando se necesita precisión importante, ya que en el fondo depende del frame rate, y si usar updateAfterEvent puede ser trágico para la CPU), el método es el mismo pero difiere la manera de ajustar ya que tendremos que controlar el tiempo REAL que ha pasado desde la anterior llamada, y compensar con el tiempo que que se había indicado en el intervalo.

Un ejemplo escrito del tirón de mala manera, pero que representa el tema:

const LAPSO_IDEAL:uint = 1000;
const INCREMENTO:uint = 10;
var controlTiempo:Timer = new Timer(LAPSO_IDEAL, 0);
var previousTime:int = getTimer();
controlTiempo.addEventListener(TimerEvent.TIMER, actualizar);
controlTiempo.start();

function actualizar(ev:TimerEvent):void
{
	var now:int = getTimer();
	var lapso_real:int = now - previousTime;
	var incremento_efectivo:Number;

	incremento_efectivo = INCREMENTO * LAPSO_IDEAL/lapso_real; 

	trace("lapso_ideal/lapso_real = "+LAPSO_IDEAL+" / "+lapso_real);
	trace("incremento efectivo: "+incremento_efectivo);

	previousTime = now;
}

Con la misma filosofía, pero diferente aplicación se logra que los incrementos en propiedades se compensen con el tiempo real de ejecución de nuestras películas, con lo que una ralentización en los procesos no hace que los elementos vayan a menor velocidad (si a saltos más grandes, pero no velocidad entendiéndola como espacio/tiempo).

Un enlace muy interesante, al igual que el blog en el que se incluye.

Versión [Q] de un clásico medidor de FPS reales (fotogramas por segundo)

Pues lo dicho, de regalo con el tip, aquí os dejamos una clase muy básica pero que como veis puede ser útil en ocasiones, que en nuestro caso te permite medir los FPS reales en el intervalo que se le indique y haciendo una media ponderada de varias “tomas”, de tal manera que el valor de FPS reales sea significativo y no se pierda por un “pico” puntual.

La manera de usarla es sencilla:

import com.qinteractiva.utils.FPSMeter;

var medidor:FPSMeter = new FPSMeter();
medidor.addEventListener(FPSMeter.FPSMETER_UPDATED, mostrarFPS);

// Se medirá contando el tiempo de ejecución de 10 ENTER_FRAME
// y con una media de 5 medidas
medidor.start(10, 5);

function mostrarFPS(ev:Event):void
{
	trace("fps: "+ev.target.getFPS());
}
Descargar FPSMeter de [Q]

Deja un comentario