Esto está empezando a cobrar forma de verdad: tenemos una estructura fácilmente ampliable para crear patrones de movimiento de alienígenas, pero son un poco inofensivos de momento, ya que no pueden disparar armas propias. ¡Vamos a remediarlo!
Primero diseñaremos un sprite de misil alienígena:

Voy a usar el Sprite Type 3 para los misiles alienígenas, pero antes de empezar a programar hay algo que tenemos que tener en cuenta: la detección de colisiones de MPAGD. Como todos los sprites miden 16 px x 16 px, pero nuestro misil alienígena solo ocupa 3 píxeles de ancho, podrían producirse colisiones bastante injustas que visualmente no parecen un misil chocando con la nave espacial del jugador, pero que el motor registra como colisión. Por eso tendremos que incluir código que ayude a comprobar si la parte gráfica del sprite ha chocado realmente con la nave espacial.
También tenemos que pensar en cómo viajan los misiles: ¿bajan simplemente en línea recta?, ¿deben perseguir al jugador?, o ¿deben desviarse a la izquierda o a la derecha según la dirección en que viajaba el alienígena cuando lanzó el misil?
Esta última opción es mi favorita y, como todas las direcciones de los alienígenas se guardan en la variable DIRECTION, debería ser bastante fácil programar la dirección del misil: si un alienígena viajaba hacia la derecha cuando soltó el misil, el misil debe desviarse hacia la derecha, y así sucesivamente.
Otras cosas que debemos tener en cuenta son:
¿Cuándo debe dispararse un misil?
¿Cuál es la probabilidad de que se dispare un misil?
¿Deben disparar todos los alienígenas con la misma frecuencia?
¿Deben disparar misiles todos los alienígenas o solo algunos?
¿A qué altura de la pantalla debe estar un alienígena para poder disparar misiles? (conviene evitar que disparen si están a solo unos píxeles por encima del jugador, porque sería injusto.)
Hasta ahora hemos construido una estructura bastante flexible, así que estoy pensando en ampliar aún más la flexibilidad para poder variar la capacidad de disparo de misiles de cada oleada de ataque de alienígenas, lo que nos ayudará a hacer las oleadas de ataque progresivamente más difíciles.
Bien, pasemos al código. Primero, vamos a ampliar el código de nuestro Spawner para incluir algunas variables nuevas que controlen las capacidades de disparo de los alienígenas. Abre tu evento Spawner (Sprite Type 7) y añade el código resaltado:
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 ; points for a kill READ C ; colour READ W ; weapon READ H ; fire weapon probability READ Q ; min height to release weapons ENDREPEAT LET D = E ; how many kills to get bonus? LET F = E ; enemies remaining 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 < 9 ; are there 8 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 ; retrun to the spawner ENDIF ELSE ; all enemies in this level have been spawned IF F = 0 ; all enemies are off screen ADD 1 TO L ; get ready for next level IF L = 7 ; 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 132 8 5 2 8 8 5 67 1 10 100 DATA 0 100 8 5 2 8 8 10 68 1 10 100 DATA 0 232 16 5 5 8 6 15 69 1 8 100 DATA 0 8 16 5 5 8 6 15 70 1 8 100 DATA 0 232 146 5 2 16 6 20 71 1 4 100 DATA 0 8 146 5 2 16 6 20 66 1 4 100
Todo lo que hemos añadido aquí son tres variables nuevas que leeremos de la tabla de datos:
W (Weapon) - 0 significará que no pueden disparar misiles, 1 que sí pueden
H (probabilidad de disparar un arma): cuanto mayor sea el valor, menos probabilidad hay de que disparen un misil realmente
Q (altura de disparo): es el valor de Y por debajo del cual (es decir, más arriba en la pantalla, ya que las coordenadas Y del Spectrum empiezan en la parte superior de la pantalla) debe estar un alienígena para que se le permita disparar misiles.
He añadido algunos valores para cada una de las 6 oleadas de ataque definidas actualmente en la tabla de datos al final.
A continuación, necesitaremos añadir un par de líneas de código a nuestro evento del jugador para guardar los valores de las coordenadas X & Y del jugador, ya que las necesitaremos en el evento del alienígena para calcular a qué distancia horizontal está el alienígena del jugador. Abre tu evento del jugador y añade estas líneas al final de tu script:
LET M = X ; store player X in M LET N = Y ; store player Y in N
A continuación, añadiremos algo de código al evento del alienígena (Sprite Type 5). Ábrelo y añade/actualiza el código resaltado:
EVENT SPRITETYPE5 ; FLEXI ALIENS ; ===================== SPRITEINK C ; colour the alien with C value IF SETTINGA = 0 ; Alien first appears RESTORE ; Restore the data table LET RND = L ; Store the Level number in RND ADD 50 TO RND ; and increase it by 50 WHILE DIRECTION <> RND ; While DIRECTION doesnt = RND READ DIRECTION ; Read value from DATA table READ SETTINGB ; Also read second value ENDWHILE ; Keep going until we find the value in RND LET SETTINGA = 1 ; When we find it change SA to 1 ENDIF IF SETTINGA = 1 ; Ready to get direction & reptitions READ DIRECTION ; Read the next movement into DIRECTION READ SETTINGB ; Read the repetitions into SettingB LET SETTINGA = 2 ; ENDIF IF COLLISION 1 ; if hit by a torpedo OTHER ; switch to torpedo LET DIRECTION = 99 ; run the explosion ENDSPRITE ; return to this Alien LET TYPE = 6 ; Switch it to explosion type LET IMAGE = 4 ; Explosion image LET FRAME = 0 ; first frame LET DIRECTION = 0 ; tell explosion its an alien exploding ENDIF IF COLLISION 0 ; if enemy and player collide LET TYPE = 6 ; switch it to the explosion type LET IMAGE = 4 ; and the explosion image LET FRAME = 0 ; reset it to first frame LET DIRECTION = 0 ; this is an alen exploding OTHER LET DIRECTION = 99 ; trigger the player explosion ENDSPRITE ENDIF IF DIRECTION = 0 ; Move N SPRITEUP SPRITEUP ENDIF IF DIRECTION = 1 ; Move NNE SPRITERIGHT SPRITEUP SPRITEUP ENDIF IF DIRECTION = 2 ; Move NE SPRITERIGHT SPRITERIGHT SPRITEUP SPRITEUP ENDIF IF DIRECTION = 3 ; Move ENE SPRITERIGHT SPRITERIGHT SPRITEUP ENDIF IF DIRECTION = 4 ; Move E SPRITERIGHT SPRITERIGHT ENDIF IF DIRECTION = 5 ; Move ESE SPRITERIGHT SPRITERIGHT SPRITEDOWN ENDIF IF DIRECTION = 6 ; MOVE SE SPRITERIGHT SPRITERIGHT SPRITEDOWN SPRITEDOWN ENDIF IF DIRECTION = 7 ; MOVE SSE SPRITEDOWN SPRITEDOWN SPRITERIGHT ENDIF IF DIRECTION = 8 ; MOVE S SPRITEDOWN SPRITEDOWN ENDIF IF DIRECTION = 9 ; MOVE SSW SPRITEDOWN SPRITEDOWN SPRITELEFT ENDIF IF DIRECTION = 10 ; MOVE SW SPRITEDOWN SPRITEDOWN SPRITELEFT SPRITELEFT ENDIF IF DIRECTION = 11 ; MOVE WSW SPRITEDOWN SPRITELEFT SPRITELEFT ENDIF IF DIRECTION = 12 ; MOVE W SPRITELEFT SPRITELEFT ENDIF IF DIRECTION = 13 ; MOVE WNW SPRITELEFT SPRITELEFT SPRITEUP ENDIF IF DIRECTION = 14 ; MOVE NW SPRITELEFT SPRITELEFT SPRITEUP SPRITEUP ENDIF IF DIRECTION = 15 ; MOVE NNW SPRITELEFT SPRITEUP SPRITEUP ENDIF ; BOUNDARY CHECKING ; =================== IF X <= LEFTEDGE ; if alien reaches the left edge REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter SUBTRACT 1 FROM F ; decrement the all aliens in wave counter ENDIF IF X >= RIGHTEDGE ; if alien reaches the right edge REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter SUBTRACT 1 FROM F ; decrement the all aliens in wave counter ENDIF IF Y >= BOTTOMEDGE ; if alien reaches the right edge REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter SUBTRACT 1 FROM F ; decrement the all aliens in wave counter ENDIF ; SHALL WE SHOOT A MISSILE? ; =========================== IF Y < Q ; is alien above minimum height for releasing missiles? IF W > 0 ; yes, can alien release missiles? IF X < M ; yes, is Alien to the right of player? SUBTRACT X FROM M ; how far to the right of player is alien? IF M <= 8 ; 8 or less pixels? LET AIRBORNE = 1 ; run the chance of firing routine ENDIF ADD X TO M ; reset M ELSE IF M < X ; is alien to the left of player? SUBTRACT M FROM X ; yes, how far to the left IF X < = 8 ; 8 pixels or less? LET AIRBORNE = 1; yes, run the chance of firing routine ENDIF ADD M TO X ; reset X ELSE ; enemy must be directly above player LET AIRBORNE = 1 ; run the chance of firing routine ENDIF ENDIF ENDIF ENDIF IF AIRBORNE = 1 ; Chance of firing routine IF S < 9 ; are there 8 or less sprites on screen? GETRANDOM H ; yes, get a random number from 0 to the aliens missile probability # IF RND = 1 ; is it 1? LET RND = DIRECTION ; yes, store aliens direction in RND SPAWN 3 6 ; spawn a missile SPAWNED ; switch to the spawned missile LET DIRECTION = RND ; set its direction to RND ENDSPRITE ; switch back to this alien ENDIF ENDIF LET AIRBORNE = 0 ; end the chance of firing routine ENDIF SUBTRACT 1 FROM SETTINGB ; decrement the repetitions IF SETTINGB = 0 ; has alien moved all repetitions? LET SETTINGA = 1 ; get the next direction & # of repetitions ENDIF DATA 51 0 8 20 7 8 6 8 5 8 4 16 DATA 52 0 8 20 9 8 10 8 11 8 12 16 DATA 53 0 12 48 11 2 10 2 9 2 8 2 7 2 6 2 5 2 4 40 5 2 6 2 7 2 8 2 9 2 10 40 DATA 54 0 4 48 5 2 6 2 7 2 8 2 9 2 10 2 11 2 12 40 11 2 10 2 9 2 8 2 7 2 6 40 DATA 55 0 13 26 14 4 15 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 4 10 40 DATA 56 0 3 26 1 4 0 4 15 4 14 4 13 4 12 4 11 4 10 4 9 4 8 4 7 4 6 40
Lee los comentarios del código resaltado y, con suerte, entenderás lo que estamos haciendo:
Comprueba si el alienígena está a menos de 8 píxeles a la izquierda y x píxeles a la derecha del jugador
si lo está, hay una probabilidad aleatoria de que se dispare un misil (siempre que además esté por encima de la distancia vertical mínima establecida en la variable Q) Y si todavía no hay demasiados sprites en pantalla
La probabilidad de que se dispare un misil es de 1 entre H (donde H se define en la tabla de datos de la oleada de ataque, en el evento del spawner.
Y si se superan todas estas pruebas, se genera un misil (type 3, Image 6)
Después, pon el valor de DIRECTION del misil generado igual que el DIRECTION en el que viajaba el alienígena cuando disparó el misil.
Ahora solo nos falta escribir el código del misil, así que abre el Sprite Type 3 y pega esto:
EVENT SPRITETYPE3 ; ENEMY MISSILE SPRITEINK 71 ; bright white SPRITEDOWN ; go down fast (3 times SPRITEDOWN SPRITEDOWN IF DIRECTION = 0 ; was alien going down when fired? ELSE ; if so, do nothing IF DIRECTION < 8 ; was alien going right? SPRITERIGHT ; make missile veer right ELSE IF DIRECTION = 8 ; was alien going straight up? ELSE ; do nothing SPRITELEFT ; alien was going left, veer missile left ENDIF ENDIF ENDIF IF COLLISION PLAYER ; has missile collided with player? IF X > M ; is missile to the right of player? SUBTRACT M FROM X ; find out how far to the right IF RND <= 10 ; 10 px or less? its a hit! OTHER ; switch to the player LET DIRECTION = 99 ; trigger the player explosion ENDSPRITE ; switch back to this event ENDIF ADD M TO X ; reset X ELSE ; not to the right IF X < M ; is missile to the left? SUBTRACT X FROM M ; yes, how far to left? IF M <= 8 ; 8 or less pixels? OTHER ;switch to the player LET DIRECTION = 99 ; trigger the player explosion ENDSPRITE ; switch back to this event ENDIF ADD X TO M ; reset M ELSE ; must have been a direct hit OTHER ; switch to the player LET DIRECTION = 99 ; trigger the player explosion ENDSPRITE ;switch back to this event ENDIF ENDIF ENDIF IF Y >= 188 ; has missile reached bottom of the screen REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter ENDIF
Así que comprobamos las colisiones con el jugador y luego calculamos cuánto de directo es el impacto, creando en la práctica una caja de impacto rápida. Puedes ajustar estos valores a tu propio juego y tus gráficos.
Una última cosa por actualizar: fíjate en que, cuando registramos un impacto en el jugador, enviamos una instrucción al sprite del jugador para poner su dirección en 99, así que tendremos que añadir una cláusula a nuestro evento del jugador. Abre tu evento del jugador y añade:
IF DIRECTION = 99 LET TYPE = 6 ; switch it to the explosion type LET IMAGE = 4 ; and the explosion image LET FRAME = 0 ; reset it to first frame LET DIRECTION = 1 ; this is the player exploding ENDIF
He hecho esto para ahorrar memoria, ya que puede haber varios sitios en el código donde hacemos explotar al jugador (fíjate en que antes sustituí los ajustes de type, image, frame y direction en la colisión Alien/Player del evento Alien, el sprite type 5). ¡Cada byte cuenta!
Bien, eso debería ser todo lo que necesitamos para dar potencia de fuego a los alienígenas... ¡hora de probar!
Por ahora me parece bien, siempre podemos refinarlo más adelante según avance el juego.
A continuación haremos un poco de limpieza y ordenaremos algunas cosas.
SIGUIENTE: PARTE 10: UN POCO DE ORDEN
