Minilop Retroware

Tutoriales de shoot 'em up · Parte 7 de 12

Vertical Shmup - Parte 7 - Una decisión de jugabilidad

2 de agosto de 2022

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!

Todos los tutoriales de shoot 'em up