Minilop Retroware

Tutoriais de shoot 'em up · Parte 7 de 12

Vertical Shmup - Parte 7 - Uma decisão de jogabilidade

2 de agosto de 2022

Comecei esta série como uma pequena homenagem nostálgica ao Arcadia da Imagine, um jogo de que eu gostava muito aos 12 anos, em 1982. Se te lembras, no Arcadia original não era preciso matar todos os inimigos de cada vaga, era preciso sobreviver ao temporizador.

Podia implementar a mesma jogabilidade neste jogo com um temporizador, mas não estou a tentar recriar o Arcadia exatamente, por isso acho que vamos fazer outra coisa.

Como alternativa, podíamos fazer com que tenhas de matar todos os inimigos de cada vaga antes de aparecer a seguinte.

Ou talvez fosse boa ideia haver uma quantidade fixa de inimigos por vaga e, depois de todos terem sido gerados, começar a vaga seguinte. Assim, para obteres a pontuação máxima tens de matar o maior número possível e, talvez, se matares todos os inimigos de uma vaga haja algum tipo de bónus ou melhoria como recompensa.

Acho que esta última abordagem é a minha preferida e é a que vou tentar para começar.

Para isso, vamos precisar de uma variável que conte os inimigos de cada vaga que já matámos. Voltemos ao código do evento do nosso Spawner (Sprite Type 7)

e acrescentemos as linhas de código destacadas abaixo.

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

Assim, lemos para E o número total de inimigos da vaga. Não vamos querer alterar esta informação durante a vaga, por isso vamos copiá-la para outra variável, D, que usaremos como contagem decrescente sempre que matarmos um inimigo.

Vamos também guardar o número de inimigos da vaga em F, e depois decrementar F sempre que um inimigo for morto ou sair do ecrã. Só passaremos ao nível / vaga seguinte quando todos os inimigos tiverem sido removidos do ecrã; caso contrário, poderíamos ter problemas, já que as vagas novas apareceriam antes de o último dos inimigos anteriores ter saído do ecrã, o que poderia estragar os nossos contadores.

Também temos de pensar no sistema de pontuação. No Arcadia, cada inimigo valia tantos pontos como o número do nível / vaga. Assim, no nível 1 cada morte valia 1 ponto, no nível 2 valia 2 pontos, e assim por diante.

Podíamos fazer o mesmo aqui com facilidade, mas, mais uma vez, não estou a tentar recriar o Arcadia exatamente e quero manter alguma flexibilidade, por isso vamos usar uma variável nova, P, que leremos da tabela DATA. Como podes ver no código destacado acima, matar um inimigo no nível 1 dará 5 pontos e matar um inimigo no nível 2 dará 10 pontos.

Também precisamos de mostrar a pontuação no ecrã. Primeiro vamos colocá-la no nosso 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

Isto serve para começar, mas precisamos que se atualize sempre que se marcam pontos. Podíamos simplesmente colocar o mesmo código no MAIN LOOP, mas na minha experiência, se queres que o teu jogo de MPAGD funcione com eficiência, o melhor é não atualizar no ecrã as pontuações e variáveis em cada ciclo, mas sim apenas quando for necessário.

Uma abordagem seria repetir as linhas de código acima em todos os eventos em que se marcam pontos, mas isso poderia tornar-se bastante repetitivo em termos de código. Em vez disso, prefiro usar uma variável como gatilho, e vou usar T.

Agora, no nosso Main Loop 1 vamos acrescentar algum 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

Assim, sempre que quisermos atualizar a barra de pontuação, bastará acrescentar LET T = 1 nos eventos relevantes.

Voltemos ao evento do nosso sprite de explosão (Type 6) e acrescentemos os gatilhos, as contagens decrescentes e o código da pontuação:

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


Agora vamos pontuar P pontos por cada morte, mas se matarmos todos os inimigos de uma vaga, D será 0 e ganharemos um bónus de 500 pontos.

Vamos testar...

Parece-me bem, o bónus está a funcionar como esperado.

Mas estes inimigos são um pouco inofensivos, por isso a seguir vamos dar-lhes armas próprias.

SEGUINTE: PARTE 8 : OS EXTRATERRESTRES CONTRA-ATACAM!

Todos os tutoriais de shoot 'em up