lunes, 11 de febrero de 2008

PONG512 (II) El desarrollo

Buenas de nuevo:

A continuación voy a destacar aquellos detalles que considero más interesantes sobre el desarrollo del juego, al mismo tiempo que hago referencias al código fuente del mismo por lo que, si estás interesado en conocer el funcionamiento interno de algunas rutinas, te recomiendo que te descargues el código y leas lo siguiente con el código al lado.

El desarrollo

Al principio todo fue muy rápido, ya que en apenas una semana ya tenía listo el engine de cambio aleatorio de tableros (ver código fuente, etiqueta RANDOM) y las dos paletas moviéndose bajo la acción de los cursores y joysticks (rutinas MOVEPLAYER1 y MOVEPLAYER2).

Hacer que la pelota rebotase contra las paletas también fue sencillo. Tanto las paletas como la pelota son sprites por hardware y, por su movimiento relativo, sólo pueden existir choques entre una paleta y la pelota. El hardware y la BIOS del MSX hacen muy bien el trabajo de detectar colisiones de sprites, dejando en la posición F3E7h el valor del registro de estado del VDP. Si el quinto bit está activo se ha producido un choque con una paleta, momento en el que hay que cambiar el sentido de la velocidad horizontal de la pelota (de esto se encarga la rutina BATREBOUND).

Pero no basta con invertir el sentido de la velocidad horizontal, ya que es en este punto cuando el ángulo de la velocidad cambia, según la posición relativa de la paleta y la pelota en el momento del choque. Aquí debo agradecer a mi amigo WYZ que me cediera amablemente la rutina que él había usado en su propia versión del PONG (el acceso a la tabla de ángulos se encuentra, también, en la rutina BATREBOUND).

Una vez llegados a este punto y con la rutina de movimiento de la pelota (MOVEBALL) que trabaja en aritmética de punto fijo (8 bits de parte entera y 8 de parte decimal para conseguir un movimiento más suave), ya se podía jugar a darle golpes a la pelotita... la cual seguía empeñada en atravesar los muros.

Detección de colisiones con los muros

Esta fue la rutina que más tiempo me llevó, ya que quería que resultara lo más aproximada a la realidad. La versión que está incluída en el juego (bajo la etiqueta WALLREBOUND) es la tercera que intenté, ya que las dos primeras siempre daban problemas en las esquinas.

La idea fundamental consiste en comprobar si se ha de cambiar el signo de alguna de las componentes de la velocidad de la pelota (horizontal y vertical). Para ello se comprueba si el carácter bajo la pelota en ese momento (que se obtiene mediante la rutina GETCHAR) la hace rebotar o no. En el peor de los casos, la pelota puede estar sobre cuatro caracteres diferentes, por lo que se calculan las coordenadas de las cuatro esquinas del sprite que la representa, pero un pixel hacia el interior de la pelota (para así simular que es redonda y no cuadrada). Se obtiene el carácter bajo esa posición y se realizan los cálculos para comprobar si hay que hacer un rebote o no.

La rutina WALLREBOUND, que realiza este trabajo, está dividida en cuatro rutinas bastante similares: @@UL, @@UR, @@LR y @@LL, que comprueban, respectivamente las esquinas superior izquierda, superior derecha, inferior derecha e inferior izquierda. Fue aquí donde eché de menos tener más registros, por lo que tuve que echar mano del conjunto alternativo de registros del Z80, utilizando el par BC' para incrementar o decrementar el signo de las componentes horizontal y vertical de la velocidad de la pelota.

Cada vez que un carácter bajo la pelota forma parte de un muro, se incrementa o decrementa b' y c' para indicar cuál sería la velocidad relativa de la pelota tras chocar contra ese carácter de forma individual. Este cálculo se repite para los cuatro caracteres y al final los signos de b' y c' son, respectivamente, los signos de las componentes horizontal y vertical de la nueva velocidad. Veamos como funciona el algoritmo al extenderlo a más de un carácter:

Si los caracteres que se encuentran bajo la pelota son A, B, C y D (para las esquinas superior izquierda, superior derecha, inferior izquierda e inferior derecha respectivamente), entonces el signo de la velocidad según los choques es el siguiente:

  • Choques contra un único carácter:
    • A -> +x, +y
    • B -> -x, +y
    • C -> +x, -y
    • D -> -x, -y
  • Choques contra dos caracteres:
    • AB -> 0, +2y
    • CD -> 0, -2y
    • AC -> +2x, 0
    • BD -> -2x, 0
  • Choques contra tres caracteres
    • ABC -> +x, +y
    • ABD -> -x, +y
    • ACD -> +x, -y
    • BCD -> -x, -y
Es fácil ver que la extensión del algoritmo funciona cuando la pelota choca contra uno, dos o tres caracteres. Si no chocase contra ninguno, tanto b' como c' serían iguales a 0, lo que significa que no hay que variar la velocidad. Esto también sucede si los cuatro caracteres forman parte de un muro, cosa que, por construcción del tablero y del juego, es imposible. Por lo tanto el algoritmo de detección de choques contra los muros funciona perfectamente.

El resto del programa no tiene mayor complicación, ya que es bastante fácil de seguir. El bucle principal se limita a llamar a las rutinas en orden. La única complicación es seguir el flujo del programa cuando se marca un gol, ya que se llama a una subrutina que se encarga de reinicializar todos los valores para volver a las posiciones iniciales de las paletas y la pelota, para finalmente retornar al bucle principal y continuar la partida.

También la zona de datos puede resultar algo confusa, porque para ahorrar tamaño, muchos de los datos son compartidos por más de un concepto (como es el caso de los tres últimos bytes de la definición del carácter del muro, que también son la definición del muro completo sin agujeros).

Descarga

En breve estará disponible una zona de descargas donde se podrán descargar todos los juegos, utilidades y códigos que vayan apareciendo en el blog... sed pacientes :D

3 comentarios:

Pypo dijo...

Bueno, me alegro que tu blog avance. La verdad es que tengo ganas de poder descargarme el juego. No lo he buscado intensamente, pero no lo he encontrado...

Venga Saph!

Como siempre mi comentario solitario (rodolí!! que no se como és en castellano).

Rintrah dijo...

Vale tio, voy a estar visitando tu blog para conseguir ese código fuente y ver si aprendo algo... estoy iniciándome en assembler, ávido de agarrar materiales bien pensados...

Un saludo, Rintrah.

Fernando dijo...

Rintrah, en cuanto pueda configurar un espacio ftp no dudes que podrás disponer del código fuente, ya que es totalmente libre... y está lleno de comentarios (uno por instrucción como mínimo).

Saludos
--
Fernando