Empecé esta serie como un pequeño homenaje nostálgico al Arcadia de Imagine, un juego que me encantaba de niño, con 12 años, allá por 1982. Si lo recuerdas, en el Arcadia original no hacía falta matar a todos los enemigos de cada oleada, sino que había que sobrevivir al temporizador.
Podría implementar la misma jugabilidad en este juego con un temporizador, pero no pretendo recrear el Arcadia exactamente, así que creo que haremos otra cosa.
Como alternativa, podríamos hacer que tengas que matar a todos los enemigos de cada oleada antes de que aparezca la siguiente.
O quizá sería buena idea tener una cantidad fija de enemigos por oleada, y que cuando se hayan generado todos empiece la siguiente. Así, para conseguir la máxima puntuación hay que matar a tantos como sea posible, y quizá si matas a todos los enemigos de una oleada haya algún tipo de bonificación o mejora como recompensa.
Creo que este último enfoque es mi favorito y es el que voy a intentar para empezar.
Para hacerlo, necesitaremos una variable que cuente los enemigos de cada oleada que hemos matado. Volvamos al código del evento de nuestro Spawner (Sprite Type 7)
y añadamos las líneas de código resaltadas a continuación.
EVENT SPRITETYPE7 ; SPAWNER ; ============ IF SETTINGA = 0 ; first time we run this LET JUMPSPEED = 0 ; reset the enemies spawned counter LET SETTINGB = 0 ; reset the timer RESTORE ; start from the beginning of the data table REPEAT L ; get the data for this level READ AIRBORNE ; get the spawner movement READ X ; get starting x position READ Y ; get starting y position READ J ; get the enemy sprite type READ K ; get the enemy image READ E ; how many enemies in this level? READ G ; delay between releasing each enemy READ P ; Number of points scored if enemy is killed ENDREPEAT LET D = E ; store the number of enemies to be killed in D LET F = E ; also store #enemies in F to count kills & exits ADD 1 TO SETTINGA ; prevent this running again ENDIF IF SETTINGB = G ; has timer reached the delay point? IF JUMPSPEED < E ; are there still enemies left to spawn? IF S <= 8 ; are there 10 or less enemies already on screen? SPAWN J K ; spawn an enemy ADD 1 TO JUMPSPEED ; increment the number spawned SPAWNED ; switch to the enemy sprite LET DIRECTION = 0 ; set its initial direction to 0 ENDSPRITE ; return to the spawner ENDIF ELSE ; all enemies in this level have been spawned IF F = 0 ; if all enemies killed or exited ADD 1 TO L ; get ready for next level IF L = 3 ; have we reached the end of the levels? LET L = 1 ; yes, start again ENDIF LET SETTINGA = 0 ; GET DATA FOR NEXT LEVEL ENDIF ENDIF LET SETTINGB = 0 ; reset the timer ENDIF ADD 1 TO SETTINGB ; increment the timer DATA 0 165 8 2 2 5 12 5 0 80 8 2 2 5 12 10
Así que leemos en E el número total de enemigos de la oleada. No queremos cambiar esa información durante la oleada, así que la copiaremos en otra variable, D, que usaremos como cuenta atrás cada vez que matemos a un enemigo.
También guardaremos el número de enemigos de la oleada en F, y decrementaremos F cada vez que un enemigo muera o salga de la pantalla. Solo pasaremos al siguiente nivel / oleada cuando todos los enemigos hayan desaparecido de la pantalla; de lo contrario podríamos tener problemas, ya que las oleadas nuevas aparecerían antes de que el último de los enemigos anteriores hubiera salido de la pantalla, lo que podría estropear nuestros contadores.
También tenemos que pensar en el sistema de puntuación. En Arcadia, cada enemigo daba tantos puntos como el número del nivel / oleada. Así, en el nivel 1 cada muerte daba 1 punto, en el nivel 2 daba 2 puntos, y así sucesivamente.
Podríamos hacer lo mismo aquí con facilidad, pero, de nuevo, no pretendo recrear el Arcadia exactamente y quiero conservar algo de flexibilidad, así que usaremos una variable nueva, P, que leeremos de la tabla DATA. Como puedes ver en el código resaltado de arriba, matar a un enemigo en el nivel 1 dará 5 puntos y matar a un enemigo en el nivel 2 dará 10 puntos.
También tenemos que mostrar la puntuación en la pantalla. Primero la pondremos en nuestro evento RESTART SCREEN:
EVENT RESTARTSCREEN LET S = 0 ; initialise the sprite counter AT 0 1 ; position the cursor at Line 0 Column 1 SHOWSCORE ; display the score
Eso sirve para empezar, pero necesitamos que se actualice cada vez que se consigan puntos. Podríamos poner simplemente el mismo código en el MAIN LOOP, pero en mi experiencia, si quieres que tu juego de MPAGD funcione con eficiencia, lo mejor es no refrescar en pantalla las puntuaciones y variables en cada ciclo, sino actualizarlas solo cuando haga falta.
Un enfoque sería repetir las líneas de código anteriores en todos los eventos en los que se consigan puntos, pero eso podría resultar bastante repetitivo en cuanto al código. En su lugar, prefiero usar una variable como disparador, y usaré T.
Ahora, en nuestro Main Loop 1 añadiremos algo de código:
EVENT MAINLOOP1 IF T = 1 ; Score bar update requested AT 0 1 ; at Line 0 column 1 SHOWSCORE ; update the score LET T = 0 ; reset the trigger ENDIF
Así, siempre que queramos actualizar la barra de puntuación, solo tendremos que añadir LET T = 1 en los eventos correspondientes.
Volvamos al evento de nuestro sprite de explosión (Type 6) y añadamos los disparadores, las cuentas atrás y el código de puntuación:
EVENT SPRITETYPE6 ANIMATE ; regular amination IF FRAME = 4 ; are we on the last frame? IF DIRECTION = 0 ; was enemy hit by a torpedo? REMOVE ; yes, remove this sprite SUBTRACT 1 FROM S ; decrement the sprite counter SUBTRACT 1 FROM D ; decrement the enemy kill countdown SUBTRACT 1 FROM F ; decrement the kill/exit countdown IF D = 0 ; have all enemies been killed? SCORE 500 ; yes, score extra 500 points ELSE ; no, still some more to kill SCORE P ; score P number of points ENDIF ELSE IF DIRECTION = 1 ; is this the player exploding? KILL ENDIF ENDIF LET T = 1 ; update the score bar ENDIF
Ahora puntuaremos P puntos por cada muerte, pero si matamos a todos los enemigos de una oleada, D valdrá 0 y conseguiremos una bonificación de 500 puntos.
Vamos a probarlo...
Me parece bien, la bonificación funciona como esperaba.
Pero estos enemigos son un poco inofensivos, así que a continuación les daremos armas propias.
SIGUIENTE: PARTE 8 : ¡LOS ALIENÍGENAS CONTRAATACAN!
