¿Un bit puede ser muy importante?
Pues sí, un bit puede significar la diferencia entre un comportamiento totalmente normal o un programa absolutamente descontrolado. Voy a contaros una historia que me ha sucedido con el QBIQS, espero que la encontréis divertida (aunque hasta que encontré el maldito bit no me reía).
Cuando he ido a enseñarles el juego a unos compañeros, quienes también me dan consejos y prueban la jugabilidad, han empezado a suceder cosas extrañísimas... la primera de todas que el juego reseteó el MSX. Luego, probándolo más nos dimos cuenta de que la música se desincronizaba, a veces se reseteaba todo, otras veces se quedaba colgado... pero siempre el problema estaba en la rutina de música.
Dicha rutina está basada en el replayer del PT3 originalmente programado por Sergei Bulba para Spectrum y adaptado por Dioniso para MSX. Esta rutina se automodifica para ganar velocidad, con lo que su ejecución debe ser en RAM. Me puse a examinar el código, comparándolo con la salida del ensamblador y me di cuenta de que la rutina de decodificación del PT3 había sido modificada de algún modo por otra parte del programa... concretamente ¡por un impacto de un QBIQ lanzado!
La única posibilidad estaba en el último cambio que había hecho cuando uno de los beta-testers del juego me dijo que los disparos iban algo lentos para su gusto. Había modificado la rutina para, en lugar a 2 pixels por frame, moverlos a 3 pixels por frame. Una vez hecho esto estaba obligado a examinar la rutina de anulación del disparo cuando éste se sale de la pantalla.
Originalmente los disparos se anulaban cuando su coordenada vertical valía -9 y yo estaba convencido de que la coordenada de origen era 179. Así que hice un cálculo rápido 179 - (-9) = 188 que no es divisible por 3, pero 189 sí lo es, así que la nueva coordenada de anulación debe ser -10 (que es $F6 en hexadecimal). Probé el disparo y funcionaba bien, así que anoté el cambio y lo di por bueno.
Sin embargo la coordenada de origen era 159, por lo que 159 - (-10) = 169 no era divisible por 3, de modo que los disparos jamás llegaban a tener la coordenada vertical igual a -10, por lo que no se anulaban. Para acelerar los cálculos existen unas tablas de desplazamiento según la coordenada vertical del disparo, pero esas tablas están pensadas para funcionar hasta el valor -15... valor que sobrepasaban los disparos.
Al aparecer coordenadas verticales para las que no estaba previsto el cálculo, los punteros para la tabla no valían y devolvían unos valores erróneos, situando el punto de impacto en una posición fuera de la zona del scroll... concretamente en el replayer del PT3.
Así que la solución ha sido volver a modificar la coordenada de anulación de los disparos, que nunca debía haber cambiado de -9 (cuyo valor en hexadecimal es $F7).
Esta es la historia de como un simple bit (encima el bit de menos peso de un byte) puede marcar la diferencia entre un comportamiento correcto y el caos.
Un programa que se dispara a sí mismo
Cuando he ido a enseñarles el juego a unos compañeros, quienes también me dan consejos y prueban la jugabilidad, han empezado a suceder cosas extrañísimas... la primera de todas que el juego reseteó el MSX. Luego, probándolo más nos dimos cuenta de que la música se desincronizaba, a veces se reseteaba todo, otras veces se quedaba colgado... pero siempre el problema estaba en la rutina de música.
Dicha rutina está basada en el replayer del PT3 originalmente programado por Sergei Bulba para Spectrum y adaptado por Dioniso para MSX. Esta rutina se automodifica para ganar velocidad, con lo que su ejecución debe ser en RAM. Me puse a examinar el código, comparándolo con la salida del ensamblador y me di cuenta de que la rutina de decodificación del PT3 había sido modificada de algún modo por otra parte del programa... concretamente ¡por un impacto de un QBIQ lanzado!
¡Hay que hacer bien las cuentas!
La única posibilidad estaba en el último cambio que había hecho cuando uno de los beta-testers del juego me dijo que los disparos iban algo lentos para su gusto. Había modificado la rutina para, en lugar a 2 pixels por frame, moverlos a 3 pixels por frame. Una vez hecho esto estaba obligado a examinar la rutina de anulación del disparo cuando éste se sale de la pantalla.
Originalmente los disparos se anulaban cuando su coordenada vertical valía -9 y yo estaba convencido de que la coordenada de origen era 179. Así que hice un cálculo rápido 179 - (-9) = 188 que no es divisible por 3, pero 189 sí lo es, así que la nueva coordenada de anulación debe ser -10 (que es $F6 en hexadecimal). Probé el disparo y funcionaba bien, así que anoté el cambio y lo di por bueno.
Sin embargo la coordenada de origen era 159, por lo que 159 - (-10) = 169 no era divisible por 3, de modo que los disparos jamás llegaban a tener la coordenada vertical igual a -10, por lo que no se anulaban. Para acelerar los cálculos existen unas tablas de desplazamiento según la coordenada vertical del disparo, pero esas tablas están pensadas para funcionar hasta el valor -15... valor que sobrepasaban los disparos.
Al aparecer coordenadas verticales para las que no estaba previsto el cálculo, los punteros para la tabla no valían y devolvían unos valores erróneos, situando el punto de impacto en una posición fuera de la zona del scroll... concretamente en el replayer del PT3.
Así que la solución ha sido volver a modificar la coordenada de anulación de los disparos, que nunca debía haber cambiado de -9 (cuyo valor en hexadecimal es $F7).
Esta es la historia de como un simple bit (encima el bit de menos peso de un byte) puede marcar la diferencia entre un comportamiento correcto y el caos.

Personalmente guardo muy buenos recuerdos de mi infancia con respecto al PONG, recuerdos que me incluyen a mí y a mi padre jugando en el bar de unos amigos con una de esas maquinitas de PONG que se conectaban a la tele. Como una de mis motivaciones para programar videojuegos es intentar que todo lo relacionado con los juegos clásicos sea heredado por las siguientes generaciones (acostumbradas ya a los chorrocientosmil polígonos texturizados moviéndose al mismo tiempo en la pantalla) me animé a refrescar mis conocimientos del ensamblador del Z80 y a programar un clon del que se considera el pionero de los videojuegos, aunque puede que no lo sea. Veamos un poquito de historia:
Así pues nació la idea de que los tableros no fueran estáticos, sino que pudieran sufrir alteraciones durante el juego. Los muros laterales eran sencillos, ya que aparecerían diversos tipos de barreras que dificultarían la tarea de marcar un gol, pero algo tenía que hacer con los muros superior e inferior. Nada más simple: si sincronizaba ambos muros podía hacer que la pelota desapareciera por arriba para reaparecer por abajo (y viceversa). Había nacido el concepto inicial del PONG512.


