Asteroids: movimiento de los sprites por toda la pantalla (paso II) #Programación retro del Commodore 64

Gracias a la nueva versión de la rutina "posicionaSprite" ya somos capaces de mover los sprites por toda la pantalla. Ahora vamos a sacar provecho de esta posibilidad.

Empezamos con la nave. Más adelante haremos lo propio con los disparos y los asteroides.

La mayor parte los cambios que tenemos que hacer se derivan de la necesidad o conveniencia de usar dos bytes para la coordenada X de la nave. Por tanto, son cambios tediosos de hacer, pero rutinarios. No tienen nada especial que entender, ni nada especial que explicar. Simplemente, hay que hacerlos.

Algunos cambios, sin embargo, sí requieren algo más de explicación. Por tanto, vamos a revisarlos todos, pero sólo nos centraremos en los que requieren algo de detalle.

Los cambios que hay que hacer para que la nave se mueva por toda la pantalla son:

  • En la declaración de variables del jugador, hay que usar dos bytes para la coordenada X de la nave, es decir, "jugadorXLo" y "jugadorXHi".
  • En la inicialización (rutina "inicializaJugador"), a la hora de posicionar el sprite de la nave con "posicionaSprite", hay que pasar los dos bytes que ahora conforman la coordenada X de la nave.
  • En la actualización de la posición del jugador (rutina "actualizaPosicionJugador"), a la hora de calcular la nueva posición de la nave con "calculaNuevaPosicionJugador", hay que pasar los dos bytes que ahora conforman la coordenada X de la nave.
  • En la rutina "calculaNuevaPosicionJugador", que calcula la nueva posición (X, Y) en función del ángulo y la velocidad, cuando se actualice la coordenada X, habrá que tener cuidado de actualizar los dos bytes. La idea básica es sumar la velocidad al byte Lo y, si hay acarreo, sumar uno al byte Hi (esto se hace con "adc $00" que, recordemos, suma $00 y el acarreo).
  • De nuevo en la actualización de la posición del jugador (rutina "actualizaPosicionJugador"), tras calcular la nueva posición de la nave con "calculaNuevaPosicionJugador", hay que verificar los límites de la nueva posición (X, Y). Hasta ahora, sólo verificábamos los límites verticales, pero ahora tenemos que verificar también los límites horizontales. Esto lo explicaremos con un poco más de detalle más adelante.
  • Al final de la actualización de la posición del jugador (rutina "actualizaPosicionJugador"), tras verificar los límites, hay que actualizar la posición del sprite a la nueva posición (X, Y). Ahora habrá que hacerlo con los dos bytes Lo y Hi, puesto que la coordenada X exige estos dos bytes, y la rutina "posicionaSprite" también.
  • En la actualización de los disparos del jugador (rutina "actualizaDisparosJugador"), al crear un nuevo disparo con la rutina "creaDisparo", puesto que el disparo nace en la posición (X, Y) de la nave, ahora hay que pasar los dos bytes Lo y Hi a "pixel2Char".

Como veis, casi todos los cambios son rutinarios (nunca mejor dicho

🙂
) y se derivan de la necesidad de usar dos bytes para la coordenada X de la nave. Sin embargo, hay un cambio en el que me gustaría profundizar, y tiene que ver con la verificación de los límites de la nueva posición (X, Y).

Hasta ahora, sólo verificábamos los límites verticales. Hacíamos esto porque hay zonas ocultas importantes (de bastantes pixels) tanto en la zona superior como en la zona inferior de la pantalla. Y como pretendíamos eliminar estas zonas ocultas, e impedir que los sprites se ubiquen ahí, verificábamos estos límites.

Sin embargo, no hacíamos lo propio con la coordenada X. Y no lo hacíamos porque comprobamos que los sprites se veían en todo el rango [1, 255]. Sólo dejaban de verse cuando X = 0 y, para un pixel, y a la velocidad de estas naves de hoy en día, sinceramente, no merecía la pena hacer nada.

Sin embargo, ahora la X puede superar el valor 255. De hecho, con dos bytes el valor máximo posible es $ffff = 65.535. Y lógicamente, no todo este rango cae dentro de la pantalla. De hecho, la X máxima que hace que el sprite se siga viendo es X = $157 = 343. Por tanto, tenemos que empezar a controlar y limitar los valores de la coordenada X.

Esto podríamos hacerlo con un código incrustado o empotrado en la propia rutina "actualizaPosicionJugador", como hacíamos con la coordenada Y. Pero la cosa se complica, porque tenemos comprobar un límite sobre dos bytes (Lo y Hi). Por tanto, para no complicar demasiado la rutina "actualizaPosicionJugador" mejor llevamos la comprobación de límites a una rutina independiente: "verificaLimitesXJugador".

Y como somos unos forofos de la coherencia en el diseño y la simetría del código hacemos lo propio con la coordenada Y (rutina "verificaLimitesYJugador"), aunque los límites sobre Y son más fáciles de verificar porque Y sólo necesita un byte.

Todo esto podemos verlo en la nueva rutina "actualizaPosicionJugador" (parte dedicada a la verificación de los límites):

Asteroids - Verificación límites

Verificar los límites en rutinas aparte, además de simplificar la rutina "actualizaPosicionJugador", tiene otra ventaja, y es que, así, esas rutinas pueden reutilizarse en más sitios, caso de ser necesario.

Si analizamos los detalles de la nueva rutina "verificaLimitesXJugador" vemos que efectivamente merece algo de explicación:

Asteroids - Verifica límites X

Esta rutina, de forma similar a lo que ocurría con la nueva "posicionaSprite", básicamente tiene dos ramas o dos formas de funcionar:

  • Cuando "jugadorXHi" toma el valor 1, es decir, cuando la nave está en la zona derecha de la pantalla. Ver etiqueta "apjXSiHi".
  • Y cuando "jugadorXHi" toma el valor 0, es decir, cuando la nave está en la zona izquierda de la pantalla. Ver etiqueta "apjXNoHi".

Cuando "jugadorXHi" toma el valor 1 y la nave está en la zona derecha de la pantalla, el límite que hay que verificar es X >= 343 = $0157. Para comprobar esto, puesto que sabemos que "jugadorXHi" vale $01 por hipótesis, llega con comprobar si "jugadorXLo" >= $57. En caso negativo, no hay que hacer nada y terminamos ("rts"). En caso afirmativo, hemos superado el límite derecho y, por tanto, mandamos el sprite a la zona izquierda. Esto lo hacemos asignando $00 a "jugadorXHi" y $19 = 25 a "jugadorXLo".

Análogamente, cuando "jugadorXHi" toma el valor 0 y la nave está en la zona izquierda de la pantalla, el límite que hay que verificar es X < 24 = $18. Para comprobar esto, puesto que sabemos que "jugadorXHi" vale $00 por hipótesis, llega con comprobar si "jugadorXLo" < $18. En caso negativo, no hay que hacer nada y terminamos ("rts"). En caso afirmativo, hemos superado el límite izquierdo y, por tanto, mandamos el sprite a la zona derecha. Esto lo hacemos asignando $01 a "jugadorXHi" y $56 = 86 a "jugadorXLo".

En definitiva, gráficamente sería algo así (el triángulo representa la nave):

Asteroids - Límites X

Con los límites verticales hacemos algo parecido, con la salvedad de que, al ser la coordenada Y una variable mono byte, el código es mucho más sencillo. Podemos ver aquí la rutina "verificaLimitesYJugador" (intervalo válido [29-221]):

Asteroids - Verifica límites Y

En definitiva, un montón de cambios en la nave derivados del movimiento ampliado en el sentido X. Pero la mayoría de estos cambios son rutinarios y se derivan simplemente del hecho de usar dos bytes para la coordenada X. El cambio en el control de límites es algo más elaborado.

Gracias a todo esto la nave ya puede moverse por toda la pantalla. Podemos verlo en la versión 18 del proyecto.


Código del proyecto: Asteroids18


Editar

Josepzin

No hay comentarios:

Publicar un comentario