• Bruce

Vertical Shmup - Part 9 - The Aliens Fight Back!

This is really starting to come together, we have an easily extensible framework for creating alien movement patterns, but they are a bit toothless at the moment as they cant fire weapons of their own, so let's remedy that!


First we'll design an Alien Missile Sprite:




I'm going to use Sprite Type 3 for the Alien Missiles, but before we start coding there's something we're going to need to consider. And that's MPAGD's collision detection - since all sprites are 16 px x 16px - but our Alien Missile only occupies 3pixels wide - this might lead to some pretty mean collisions which visually dpnt appear to be a missile colliding with the player's spaceship - but will be registered by the engine as a collision, so we'll need to include some code that will help check whether the graphical part of the sprite has actually collided with the spaceship.


Also, we need to consider how the missiles travel, do they just go straight down?, should they home in on the player? or should they veer to the left or right dependent on the Alien's direction of travel when they launched the missile.


This latter approach is my favourite, and, since all of the Alien Directions are stored in the DIRECTION variable, it should be pretty easy to code the direction of the missile, so if an alien is travelling right when they released the missile then the missile should veer to the right, and so on.


Other things we need to consider include:


  • When should a missile be fired?

  • What is the probability of a missile being fired?

  • Should all Aliens fire at the same rate?

  • Should all Aliens fire missiles or only some?

  • How high up the screen should an alien be before they are allowed to fire missiles? (we might want to avoid them firing if they are just a few pixels above the player as that would be unfair.


We've built quite a flexible framework so far - so I'm thinking we could extend the flexibility further to allow us to vary the missile firing capabilities of each alien attack wave, that will help us make the attack waves progressively harder.


OK, so, on with the coding, first, lets extend our Spawner code to include some new variables for controlling the Aliens weapon firing capabilities, open up your Spawner event (Sprite Type 7, and add the highlighted code:



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

All we've added here is three new variables that we will read in from the data table:


W (Weapon) - 0 will mean they can't fire missiles, 1 means they can

H(Probability of firing a weapon) the higher the value the less chance they will actually fire a missile

Q (firing height) this is the Y value below which (i.e. higher up the screen since Spectrum Y co-ordinates start at the top of the screen ) an alien must be if they are allowed to fire missiles..


I've added in some values for each of the 6 currently defined attack waves in the Data table at the bottom.



Next, we're going to need to add a couple of lines of code to our player event that will Store the players X & Y coordinate values as we're going to need to use these in the Aliens event to calculate how far, horizontally, the alien is from the player, open up your player event and add these lines at the bottom of your script:




LET M = X			; store player X in M
LET N = Y			; store player Y in N






Next, we'll add some code to the Alien event (Sprite Type 5), open yours up and add/update the highlighted code:



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

 


Read through the comments in the highlighted code and hopefully you'll understand what we are doing:


  1. Check to see if the ALien is with 8 pixels to the left and x pixels to the right of the player

  2. if they are, theres a random chance that a missile will be fired (provided they are also above the minimum vertical distance as set in variable Q) AND if there arent already too many sprites on screen

  3. The probability of a missile being fired is 1 in H (where H is defined in the attack wave data table in the spawner event.

  4. And if all these tests are passed spawn a missle (type 3, Image 6)

  5. Then set the DIRECTION value of the spawned missile to be the same as the DIRECTION the alien was travelling in when they fired the missile.


Now all we need to do is write the missile code, so open up Sprite Type 3 and paste in this:



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




So, we check for collisions with the player and then calculate how much of a direct hit it is, effectively creating a quick hit box, you can adjust these values to suit your own game and graphics.


One final thing to update, notice when we register a hit on the player we send an instruction to the player sprite to set its direction to 99, so we'll need to add a clause to our player event as follows ,open up your player event and add:



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



I've done this to save memory, since there may be multiple places in the code where we explode the player (notice I replaced the type, image, frame & direction settings in the Alien/Player collision in the ALien event (sprite type 5) earlier. Every byte counts!


OK, that should be everything we need to give the Aliens their firepower...time for a test!





That looks OK to me for now, we can always refine it later as the game progresses.


Next we'll do a bit of housekeeping and tidy some stuff up.


NEXT: PART 10 - A SPOT OF HOUSEKEEPING

1 view0 comments

Recent Posts

See All

A couple of people have asked for some tutorials on creating a Vertical Shoot-em up with MPAGD, something along the lines of Imagine's classic, Arcadia. This sounded like a good challenge....but one I

Want to support my work?....Buy my games!

aboutME

Hello, I'm Bruce and I write games for old 8bit computers using Jonathan Cauldwell's excellent Multi-Platform Arcade Games Designer (MPAGD)

I've written a few successful* games for the Sinclair ZX Spectrum and MSX platforms that have been (largely) well received with my most recent game - Twenty Four Hour Parsley People scoring a 10 out of 10 on Planeta Sinclair.

In my blog I am sharing lots of the code that I wrote for my games, in a way that you can use in your own games.   I've commented it so that you'll learn some of the techniques I use to create interesting new mechanics and help your games stand out from the pack.

MPAGD includes lots of standard scripts, they're great to get you started, but if you're new (or just rusty) when it comes to writing code, hopefully my tutorials will help you get started and  turn your imagination into awesome 8 bit games!

All my code is free to use and do with as you please, but if you find them useful please feel free to buy me a coffee ...or better still - buy or download my games :)

*successful is a very relative term in 8bit computer games