Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

Como funciona el Gameloop de un Videojuego en Windows

–PeekMessage, Gameloop y Sincronización–

Esta vez no voy a perder tiempo con mis nuevos lectores no comprometidos con la programación en ensamblador y me voy a concentrar en explicar el Gameloop con PeekMessage, total. Por este tiempo voy a estar muy ocupado programando. Ya dejaremos las discusiones para pasado marzo cuando los números de VG Chartz nos den un enfoque objetivo de lo que realmente pasa en “la industria”. No vayan a pensar que porque mi actividad en otros foros baje es que estoy tramando algún plan siniestro, a menos que consideren peligroso el minijuego en ASM en el que me estoy concentrando en este momento. Bien, ahora a programar.

toma externa

En esta imagen vemos un diagrama de flujo o flowchart de un ciclo de mensajes. Al igual que en el anterior, las rutinas en azul son procesos del Windows y las grises son rutinas del usuario. Para quienes no han leido sobre programación mas que lo que les obligan a leer en la escuela, los rectángulos con dos rayas verticales a los lados son subrutinas que están definidas en otro lugar y que devuelven el control al programa principal cuando terminan. Subrutina, función, procedimiento, método, en este caso significa lo mismo. Entonces comencemos con PeekMessage

PeekMessage, a diferencia de GetMessage no se sienta a esperar a que el sistema operativo le envíe un mensaje. En lugar de eso lo que hace es echar un rápido vistazo (que es lo que en inglés significa el verbo “peek”) a la entrada de mensajes del mismo modo que uno hace cuando se asoma a ver si el cartero le ha dejado una carta en el buzón. Una vez echada esta rápida mirada regresa en el acumulador un cero en caso de no encontrar un mensaje y un valor diferente de cero en caso contrario para luego seguir su camino. PeekMessage tiene casi los mismos argumentos que GetMessage pero incluye uno extra que le dice que debe de hacer en caso de encontrar un mensaje, en el caso de un juego debe de enviarse en este argumento la constante PM_REMOVE para que tome el mensaje si lo encuenta y lo copie en la estructura de mensajes que le tenemos reservada en la sección de datos. Luego procesamos el mensaje con TranslateMessage y DispatchMessage como en el ciclo tradicional.

Y es justo a partir de este punto cuando interviene el Gameloop. Independientemente de si se procesó un mensaje o no, en cada iteración debe hacerse el intento de entrar al Gameloop. Mas adelante veremos el detalle de como se sincroniza este último con el ciclo de mensajes. Inmediatamente luego de ejecutar una iteració del gameloop se revisa el contenido de una bandera que nos indica si debemos de terminar el prorama. En este caso le puse el elegante nombre de fuck_off que podría traducirse al castellano como “irnos al demonio”. Si la bandera está puesta a cero entonces volvemos a ejecutar otra iteración del ciclo de mensajes y si es falsa salimos del ciclo, ejecutamos la rutina para cerrar el juego y terminamos el programa.


Sincronización del MessageLoop y el Gameloop

Con esta programacion, en cada iteración se va a ejecutar una vez el ciclo de mensajes y una vez el ciclo del gameloop. Pero esto puede ser demasiado rápido para la acción del juego, sobre todo en computadoras muy poderosas. Si no se mantiene la velocidad del Gameloop a un nivel constante el juego puede volverse incontrolable. En los viejos tiempos de los sistemas monotarea bastaba con revisar el reloj interno del sistema, checar la hora de entrada del ciclo y sumarle a esta una constante para calcular la hora de salida y luego entrar a un ciclo y no salir de él hasta que el reloj interno marcara la hora de salida. Aunque esto es posible en Windows, si lo hacemos podemos dejar colgada la aplicación o en el menor de los casos obtendríamos una velocidad de respuesta del sistema muy pero muy pobre. Pues pasaríamos demasiado tiempo congelados en el Gameloop y no podríamos recibir y procesar los mensajes del sistema. Entonces
¿Cual es la solución?

El ciclo de mensajes y el Gameloop pueden estar en las siguientes circunstancias uno frente al otro: En la primera el ciclo de mensajes va mucho mas rápido que el del juego y en la segunda ambos ciclos van a la misma velocidad. Bajo ninguna circunstancia el ciclo Gameloop debe de ir mas rápido que el de los mensajes o el sistema va a dejar de responder a las entradas del usuario. Pues una vez que se ha entrado a la iteración del gameloop no hay manera de procesar los mensajes. Por lo que es en la rutina de procesamiento de mensajes o Window Procedure donde las rutinas de respuesta deben de determinar que es lo que va a pasar en la siguiente iteración del juego. Ahora veamos como se evita que el juego corra mas rápido de lo deseado.

A diferencia de los sistemas antiguos, nosotros no podemos paralizar la aplicación dentro de la iteración del Gameloop, pero podemos dejar que el CPU pase mas tiempo en la sección de los mensajes. La manera de hacer esto no es muy diferente a como se hacía en la antiguedad. La idea es esta: Si tenemos un tiempo fijo de 1/60 segundos para cada iteración del gameloop necesitamos que este solo se ejecute sesenta veces por segundo. Para eso antes de entrar a la primera iteración tomamos la hora del sistema y le sumamos 1/60 segundos. Esa es la hora de entrada del gameloop y no puede entrar antes. De modo que al llamar a Gameloop lo primero que se hace es tomar la hora actual del sistema y compararla con esa hora de entrada, si la hora actual es mayor a la hora de entrada el ciclo se ejecuta y se determina la siguiente hora de entrada sumándole a la hora actual 1/60 segundos; de lo contrario se termina el gameloop sin haber hecho nada. El Gameloop puede y debe de ejecutarse en menos de 1/60 segundos pero el CPU va a pasar todo el tiempo que le sobre esperando y procesando mensajes hasta que sea de nuevo hora de entrar al gameloop. Con esto se obtiene un juego rápido, jugable y que a la vez tenga buena respuesta de las entradas del usuario.

Ya para terminar, solo nos faltan dos cosas para terminar el asunto del Gameloop, una rutina para medir su velocidad y por supuesto una manera de salir de él, pues de no hacerlo estaríamos atorados en un ciclo infinito. Ese tema lo discutiremos en la siguiente entrada donde se va a hablar de como demonios se procesan los mensajes del sistema dentro de un juego.

enero 29, 2011 - Posted by | Uncategorized | , , ,

Aún no hay comentarios.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: