Con el cambio que hemos hecho de meter una pantalla inicial, volver a esa pantalla al final de la partida, y permitir sucesivas partidas, hay un cambio fundamental: el juego ya no se ejecuta una única vez; puede ejecutarse varias veces sucesivas. Por eso ahora hablamos de “partidas” y de “sesión de partidas”.
Esto tiene sus implicaciones en cuanto a la inicialización del jugador, los asteroides y la pantalla. Hasta ahora, estaba previsto que esas inicializaciones se ejecutaran sólo una vez. A partir de ahora, tendrán que ejecutarse varias veces, una vez al comienzo de cada partida.
Pongamos como ejemplo el jugador. Su inicialización hasta ahora era así:
Pero esto no es del todo cierto, porque ese código va precedido de una declaración de variables (posiciones de memoria) del jugador que no es sólo eso, una mera declaración, sino que también se aprovecha para dar valores iniciales a algunas variables (estado, posición, velocidad, ángulo, retardos, vidas, puntos, nivel, etc.):
Al cargar el juego, esas variables se cargan con su valor inicial. Al jugar, su valor se modifica. Por tanto, si al terminar la partida y empezar otra nos limitamos a ejecutar la inicialización tradicional hasta ahora (“jsr inicializaPantallaJuego”, “jsr incializaJugador” y “jsr inicializaAsteroides”), esas variables no recuperarán su valor inicial. Heredarán los valores de la partida anterior.
Por tanto, tenemos que hacer algo para asegurarnos de que cada partida empieza con la situación inicial que queremos.
Una primera posibilidad sería convertir la declaración de variables en una mera declaración o reserva de posiciones de memoria, pero sin aprovechar para dar valores iniciales. Por tanto, todo se declararía como byte $00. Y esos valores iniciales podrían fijarse mediante instrucciones “lda <valor>” y “sta <variable>” en el cuerpo de las inicializaciones (rutinas “inicializaPantallaJuego”, “incializaJugador” y “inicializaAsteroides”). Por ejemplo:
Otra posibilidad, que es por la que hemos optado al final, es no tener los valores iniciales “por código”, es decir, en instrucciones “lda <valor>” y “sta <variable>”, sino tenerlos en secciones de memoria, y copiar esas secciones a las variables al comienzo de las rutinas de inicialización. Lo mejor es verlo con un ejemplo:
Como se puede observar, las variables van precedidas por una sección de memoria delimitada por las etiquetas “jugadorConfComienzo” y “jugadorConfFin”. Esta sección de memoria incluye, a modo de plantilla, los valores iniciales de las variables. No hace falta incluir ahí lo que sean constantes que no se modifican (“jugadorSprite”, “jugadorFrames”, “explosionFrames”, …), ni tampoco variables como “jugadorMaxPuntos” (el record), que sí deben heredarse o mantenerse de una partida a la siguiente.
Y ahora, en la rutina de inicialización “incializaJugador”, empezamos por copiar esos valores a las variables. Para ello, llamamos a la nueva subrutina “inicializaVariablesJugador”, que se basa la rutina “copiaBloque” de la librería “LibChars”:
De este modo, en cada partida, al ejecutarse la inicialización del jugador, se empieza por inicializar sus variables.
Con los asteroides hacemos exactamente lo mismo para inicializar sus variables: la rutina “inicializaAsteroides” empieza llamando a la nueva subrutina “inicializaVariablesAsteroides”.
Por último, en el caso de las pantallas, en teoría haría falta lo mismo. Sin embargo, aunque las pantallas tienen inicializaciones, las pantallas no utilizan variables y, por tanto, lo anterior no es necesario.
En definitiva, una lección importante que hemos aprendido con esta entrada es que, si nuestro juego va a tener partidas sucesivas (lo cual es muy habitual), no debemos apoyarnos en las inicializaciones que suelen acompañar a las declaraciones de variables. Mejor hacer esas inicializaciones por código, porque así podremos repetirlas con comodidad.
Todo esto puede verse, también, en la versión 20 de proyecto.
Código del proyecto: Asteroids20