Minilop Retroware

Tutoriales de shoot 'em up · Parte 8 de 12

Vertical Shmup - Parte 8 - Un enfoque más flexible para los alienígenas

2 de agosto de 2022

Hasta ahora tenemos dos oleadas de alienígenas y son bastante fáciles de derrotar, pero veo un problema en cómo lo hemos escrito. En el juego espero tener muchos patrones de movimiento distintos para los alienígenas, estoy pensando en un estilo Galaga, o al menos en las partes en las que los alienígenas entran volando en la pantalla.

Con nuestro patrón inicial de alienígenas hubo cierto grado de reutilización de código, pero creo que podemos aprovechar de verdad los comandos DATA & READ de MPAGD para encontrar un enfoque mucho más flexible, que nos permita crear rápidamente infinitos patrones de movimiento de alienígenas (¡o al menos hasta que nos quedemos sin memoria!

Primero crearé un sprite nuevo de nave alienígena:

Captura de pantalla del tutorial

Voy a empezar un Sprite Type nuevo para mis nuevos alienígenas flexibles... Usaré el Sprite Type 5.

Pensemos en las posibles direcciones en las que puede moverse un alienígena. Creo que las 16 direcciones ampliadas de la rosa de los vientos nos darán suficiente flexibilidad:

Captura de pantalla del tutorial

Luego escribiremos código de movimiento para cada punto cardinal, usando la variable local DIRECTION, empezando por 0 para N, 1 para NNE y así sucesivamente en el sentido de las agujas del reloj:

EVENT SPRITETYPE5

ANIMATE SLOW

							; FLEXI ALIENS
							; =====================
							

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

Bien, eso definirá cada uno de los movimientos posibles de un alienígena. Ahora solo necesitamos una forma de definir un patrón de movimientos, que podría ser tan simple como una secuencia de valores para DIRECTION y el número de repeticiones.

Así, 8 20 significaría: realiza la DIRECTION 8 (sur) 20 veces.

Si recuerdas nuestro método anterior para mover la primera oleada de alienígenas, iban hacia el sur y luego se desviaban hacia el suroeste,

En nuestro método nuevo eso podría representarse así:

8 20 (sur 20 veces)

7 8 (SSE 8 veces)

6 8 (SE 8 veces)

5 8 (ESE 8 veces)

4 16 (E 16 veces)

Lo cual se presta perfectamente a guardarse en una tabla DATA, por ejemplo:

DATA 8 20 7 8 6 8 5 8 4 16

Después podríamos crear fácilmente patrones nuevos que describan el movimiento de los alienígenas de cada nivel, solo en este evento.

¡Eso debería ser muy eficiente!

Pero hay un par de cosas que necesitaremos para que funcione:

1) Una variable para guardar el número de repeticiones de la dirección de movimiento actual

2) Una forma de encontrar el punto de partida correcto del patrón específico para el nivel / oleada.

El punto 1 es bastante fácil de resolver: simplemente usaremos SETTINGB para leer en ella el número de repeticiones

Usaremos SETTINGA como variable de control, para asegurarnos de que hacemos las cosas en el momento adecuado

Y usaremos JUMPSPEED como contador del número de repeticiones.

Añade el código resaltado a tu evento SPRITE TYPE 5:

EVENT SPRITETYPE5



							; FLEXI ALIENS
							; =====================
SPRITEINK C					; Colour the aliens							
				
							
							; FIND THE STARTING POINT FOR THIS LEVEL
							;=======================================
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
							; GET THE NEXT DIRECTION & # REPETITIONS
							;=======================================
IF SETTINGA = 1				; Ready to get direction & reptitions
	READ DIRECTION    		; Read the next movement into DIRECTION
	READ SETTINGB     		; Read the repetitions into SettingB
	LET JUMPSPEED = 0			; reset the counter
	LET SETTINGA = 2			; now we are ready to move
ENDIF

							; MOVEMENTS
							;==============
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 number of aliens still in
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 number of aliens still in
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 number of aliens still in
ENDIF


		; INCREMENT REPETITION COUNTER & CHECK IF WE NEED NEXT DIRECTION
		;============================== 
SUBTRACT 1 FROM SETTINGB	; decrement the number of repetitions
IF SETTINGB = 0			; have we done all the required repetitions
	LET SETTINGA = 1		; yes, request the next direction
ENDIF



; MOVEMENT & REPETITIONS DATA TABLE

DATA 51 0 8 20 7 8 6 8 5 8 4 16
DATA 5e2 0 8 20 9 8 10 8 11 8 12 16

Primero, he añadido un comando spriteink para colorear a los alienígenas con el valor C (lo añadiremos a la tabla de datos del spawner dentro de un momento)

Así, cuando este evento se ejecute por primera vez para un sprite alienígena, SettingA valdrá 0 (tendremos que añadirlo a Initialise Sprites dentro de un momento)

Esto restaurará la tabla de datos (lo que significa que el siguiente READ será el primer valor de la tabla). Después recorreremos los datos hasta encontrar un valor igual a 50 + el número de nivel (es decir, para el nivel 1 buscamos 51, para el nivel 2 buscamos 52 y así sucesivamente).

Elegí 50 porque es improbable que necesite más de 50 direcciones (0-15 representan nuestros 16 puntos cardinales), pero me deja margen para añadir más después y significa que podría tener más de 200 patrones de movimiento en este evento, lo que debería ser más que suficiente.

Una vez que lo hayamos encontrado, leeremos el número siguiente en SETTINGB (usaremos simplemente 0) y pondremos SettingA a 1 para no restaurar los datos en cada ciclo.

Es importante entender que cada sprite sabe siempre hasta dónde ha leído de la tabla de datos, a menos que hagamos un RESTORE, momento en que vuelve al principio.

Ahora que SettingA vale 1, haremos un READ del número de DIRECTION y del número de REPETITIONS necesarias en SETTINGB, y luego pondremos settingA a 2 para evitar que esto se ejecute de nuevo hasta que se hayan realizado todas las repeticiones de la dirección de movimiento.

Ten en cuenta que también he puesto una comprobación de límites (no muy eficiente, la mejoraremos más adelante) que eliminará a los alienígenas que salgan de la pantalla.

Por último, tenemos nuestra tabla DATA. Por el momento he replicado nuestros dos patrones de movimiento originales: bajar y desviarse a la derecha, y bajar y desviarse a la izquierda.

Bien, antes de probarlo nos quedan un par de tareas más.

MENÚ: EVENTS > INITIALISE SPRITES:

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 5				; FLEXI ALIENS
	LET SETTINGA = 0		; Initialise SettingA
ENDIF

IF TYPE 7				; SPAWNER
	LET SETTINGA = 0		; RESET SETTINGA	
ENDIF

A continuación, actualizaremos el código del evento del Spawner:

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
	READ C				; get the colour value for the alien
	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 132 8 5 2 8 8 5 67 
DATA 0 100 8 5 2 8 8 10 68

Aquí he añadido un valor nuevo a cada conjunto de datos y he separado los dos niveles en líneas propias para que sea más fácil de leer. El valor nuevo (el noveno) es el que se leerá en C.

¡Creo que estamos listos para probar! ¡Vamos a compilar a este bicho!

¡Sí! ¡Mira cómo vuelan!

Vale, ahora vamos a divertirnos y a crear algunos patrones nuevos en la tabla DATA del sprite type 5. Asegúrate de empezar cada patrón con 200+Nivel# seguido de un cero y luego tus pares de DIRECTION # y Repetition #

Prueba estos para empezar, y luego inventa los tuyos:

Sustituye la tabla DATA de tu evento de alienígena (Sprite Type 5) por:

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

Y sustituye la tabla de datos de tu Spawner (Sprite Type 7) por:

DATA 0 132 8 5 2 8 8 5 67 
DATA 0 100 8 5 2 8 8 10 68
DATA 0 232 16 5 5 8 6 15 69 
DATA 0 8 16 5 5 8 6 15 70 
DATA 0 232 146 5 2 16 6 20 71 
DATA 0 8 146 5 2 16 6 20 66 

Ahora que tenemos 6 oleadas de ataque / niveles, tendrás que actualizar esta línea en el evento de tu spawner

			IF L = 3			; have we reached the end of the levels?
			

a:

			IF L = 7			; have we reached the end of the levels?

Guarda tu juego, ¡y vamos a compilarlo y a disparar a unos cuantos alienígenas!

¡Genial! ¡Siéntete libre de experimentar y de crear muchos más patrones de ataque!

Sin embargo, ya va siendo hora de darles a los alienígenas armas propias. Si nos apoyamos en la estructura que ya hemos creado y usamos algunos de los trucos que hemos aprendido, deberíamos poder añadir mucha más variedad al juego.

SIGUIENTE: Parte 9: ¡Los alienígenas contraatacan!

Todos los tutoriales de shoot 'em up