Para empezar, voy a crear un sprite de nave alienígena y luego escribir algo de código para su movimiento.

En la primera oleada de ataque quiero que un flujo de estos tipos aparezca por la parte superior de la pantalla, baje en línea recta y luego se desvíe hacia un lado de la pantalla.
Quiero que el flujo de alienígenas aparezca en dos puntos de la parte superior de la pantalla, uno a la derecha del centro y otro a la izquierda.
El flujo de la derecha debe desviarse hacia el borde derecho, y el de la izquierda hacia el borde izquierdo.
Pero para empezar, vamos a dejar resuelto el movimiento básico. Usaremos el Sprite Type 2 para este alienígena:
MENÚ: EVENTS > SPRITE TYPE 2
IF IMAGE 2 ; ALIEN 1 image SPRITEINK 4 ; green IF DIRECTION = 0 ; initial direction (setup) IF X <= 128 ; is alien on left side of screen? LET DIRECTION = 1 ; yes, set its direction to 1 ELSE LET DIRECTION = 2 ; no, set its direction to 2 ENDIF ENDIF IF Y < 80 ; is alien above the 80px y line? SPRITEDOWN ; move down SPRITEDOWN ; and again (faster) ELSE ; alien is below the 80 px y line IF Y < 120 ; is it betwwwn 80 and 119 y? IF DIRECTION = 1 ; yes, is it on the left side? SPRITEDOWN ; yes, go down SPRITELEFT ; and go left ELSE ; no, its on the right side SPRITEDOWN ; so go down SPRITERIGHT ; and go right ENDIF ELSE ; alien is below the 120 y line IF DIRECTION = 1 ; is it on the left side? SPRITELEFT ; yes, go left SPRITELEFT ; and left again SPRITEDOWN ; and go down ELSE ; if its on the right side SPRITERIGHT ; go right SPRITERIGHT ; go right again SPRITEDOWN ; and go down ENDIF ENDIF ENDIF ; BOUNDARY CHECKING ; =================== IF X <= LEFTEDGE ; if alien reaches the left edge REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter ENDIF IF X >= RIGHTEDGE ; if alien reaches the right edge REMOVE ; remove it SUBTRACT 1 FROM S ; decrement the sprite counter ENDIF ENDIF
Ahora añadiremos dos de estos tipos a nuestra pantalla: pondremos uno a la izquierda del centro, arriba, y otro a la derecha del centro, y asignaremos a cada uno el Sprite Type 2. El código de arriba debería averiguar dónde está cada uno y establecer su movimiento en consecuencia.
MENÚ: EDITOR > SPRITE POSITIONS

Vamos a compilar el juego a ver qué pasa
{INSERT VIDEO}
Vale, no está mal, podemos refinarlos y mejorarlos más adelante.
Pero primero tenemos un problema mayor que resolver. ¿Cómo hacemos que aparezca un flujo de estos tipos?
Podría simplemente crear una pantalla para cada nivel, diseñar algunos sprites, escribir código de movimiento y usar las posiciones de sprites para definir sus puntos de partida, pero no creo que eso fuera el uso más eficiente de la memoria disponible.
Voy a adoptar un enfoque distinto: definiré un sprite Spawner, un sprite invisible cuya tarea es colocar enemigos en la pantalla en el momento adecuado.
El Spawner necesita tener propiedades propias, como:
Si está en una posición fija o si se mueve
Qué alienígenas genera (su imagen y su tipo de sprite)
¿Cuánto debe esperar entre cada aparición?
¿Cuántos alienígenas debe generar en cada oleada de ataque / nivel?
Este es un escenario ideal para guardar cada una de estas propiedades en una tabla DATA y luego leerlas con READ según haga falta.
Pero primero, vamos a crear el sprite Spawner creando un sprite nuevo con una imagen en blanco.

Antes de empezar a programar nuestro Spawner crearemos una variable nueva, 'L', que contendrá el nivel del juego: empezará en 1, el primer nivel, y avanzará a medida que el jugador derrote cada oleada de ataque.
MENÚ: EVENTS > GAME INITIALISATION
EVENT GAMEINIT LET L = 1 ; Level (starts at 1)
A continuación definiremos el Spawner en el Sprite Type 7 y escribiremos algo de código:
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 ENDREPEAT 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 ; retrun to the spawner ENDIF ELSE ; all enemies in this level have been spawned ADD 1 TO L ; get ready for next level IF L = 2 ; have we reached the end of the levels? LET L = 1 ; yes, start again ENDIF LET SETTINGA = 0 ; GET DATA FOR NEXT LEVEL ENDIF LET SETTINGB = 0 ; reset the timer ENDIF ADD 1 TO SETTINGB ; increment the timer DATA 0 165 8 2 2 5 12
Bien, aquí es donde la cosa se complica un poco, pero ten paciencia conmigo, intentaré explicarlo lo más sencillo posible. Vamos a usar algunas de las funciones menos conocidas de MPAGD que no están disponibles en el AGD normal ni siquiera en AGDx, pero cuando las entiendas te garantizo que empezarás a crear mejores juegos.
Hablo de READ y DATA. Los he usado a fondo en todos los juegos que he publicado: me han ayudado a ahorrar memoria, a escribir mejor código, a crear mecánicas nuevas e interesantes y mucho más. En mi opinión, son las mejores funciones de MPAGD.
Lo que hace básicamente el código de arriba es:
Cuando el spawner aparece por primera vez, lee el primer número de la tabla DATA y lo guarda en la variable de sprite AIRBORNE (¡ya lo explicaré!)
Lee el segundo número de la tabla de datos: será la posición X del Spawner
Lee el tercer número de la tabla de datos: será la posición Y del Spawner
Lee el cuarto número de la tabla de datos: nos dirá el número de Sprite Type del alienígena que se generará
Lee el quinto número de la tabla de datos: nos dirá el número de imagen de sprite del alienígena que se generará
Lee el sexto número de la tabla de datos: nos dirá cuántos enemigos hay que generar en esta oleada de ataque / nivel
Lee el séptimo número de la tabla de datos: nos dirá cuánto debe esperar el spawner antes de generar el siguiente alienígena
La tabla DATA, por el momento, solo contiene los datos de la primera oleada de ataque:
0 (AIRBORNE) Define el patrón de movimiento del propio spawner, aunque no lo usaremos en esta primera ocasión
165 (X) la coordenada x del spawner
8 (Y) la coordenada y del spawner
2 (J) el número de tipo de sprite del alienígena
2 (K) el número de imagen de sprite del alienígena
5 (E) el número de alienígenas de esta oleada de ataque
12 (G) el número de ciclos de cpu que hay que esperar entre la aparición de un alienígena y el siguiente
Antes de probar nuestros avances, necesitamos inicializar el valor de SETTINGA a 0 cuando se genera el Spawner por primera vez
MENÚ: EVENTS > INITIALISE SPRITES
y añadir el código resaltado:
EVENT INITSPRITE ADD 1 TO S ; increment the sprite counter IF TYPE 1 ; PHOTON TORPEDO LET SETTINGB = 0 ; initialise the distance counter ENDIF IF TYPE 7 ; SPAWNER LET SETTINGA = 0 ; RESET SETTINGA ENDIF
Vamos a ejecutarlo y comprobar que todo va como esperamos.
Sí, parece que está bien
Ahora vamos a añadir los datos de la siguiente oleada. Esta vez pondremos el Spawner a la izquierda del centro. En el evento de tu spawner añade/actualiza el código resaltado, que añadirá los datos de la siguiente oleada / nivel
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 ENDREPEAT 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 ; retrun to the spawner ENDIF ELSE ; all enemies in this level have been spawned 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 LET SETTINGB = 0 ; reset the timer ENDIF ADD 1 TO SETTINGB ; increment the timer DATA 0 165 8 2 2 5 12 0 80 8 2 2 5 12
Ahora vamos a compilarlo de nuevo:
{insert video}
Vale, tiene buena pinta: vemos la primera oleada a la izquierda y luego la segunda a la derecha, y el patrón se repite en bucle.
Más adelante ampliaremos las capacidades del Spawner, pero como puedes ver en el vídeo de arriba, el juego tiene un problema fundamental: no pasa nada cuando los torpedos del jugador alcanzan a los alienígenas.
Así que lo abordaremos a continuación...
PARTE 6: ELIMINAR ALIENÍGENAS
