• Bruce

Vertical Shmup - Part 8 - A more flexible approach to Aliens

So far, we have two waves of aliens, and they're pretty easy to defeat, but I can see a problem with the way we wrote it. In the game I hope to have lots of different Alien movement patterns, I'm thinking Galaga style - or at least the parts where the Aliens fly into the screen.


With our initial Alien pattern there was a degree of code re-use, but I think we can really take advantage of MPAGDS DATA & READ commands to come up with a far more flexible approach, which could quickly help us create infinite alien movement patterns (or at least, until we run out of memory!


First I'll create a new Alien Ship Sprite:



I'm going to start a new Sprite Type for my new flexi-aliens...I'll use Sprite Type 5.


Let's consider the possible directions an Alien can move in, I'm thinking the extended 16 compass directions should give us enough flexibility:



We'll then write some movement code for each of the compass points, using the DIRECTION local variable, starting at 0 for N, 1 for NNE and so on in a clockwise fashion:



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


OK, so that will define each of the possible movements that an Alien can perform, now all we need is a way to define a pattern of movements, this could be as simple as a sequence of values for the DIRECTION and the number of repetitions.


So, 8 20 would mean, perform the # DIRECTION (South) 20 times.


If you think back to our previous method of moving the first wave of aliens, they went South, then veered off to the south west,

In our new method that could be represented as:


8 20 (south 20 times)

7 8 (SSE 8 times)

6 8 (SE 8 times)

5 8 (ESE 8 times)

4 16 (E 16 times)


Which lends itself perfectly to be stored in a DATA table. e.g:


DATA 8 20 7 8 6 8 5 8 4 16


We could then simply create new patterns that describe the movement of the aliens for each level, in just this single event.


That should be really efficient!


There's a couple of things we'll need though to make this work:


1) A variable to store the number of repetitions of the current movement direction

2) A way to find the right starting point for the pattern specific to the level/wave.


1, is pretty easy to handle, we'll just use SETTINGB to read into for the number of repetitions


We'll use SETTINGA as a control variable, that ensures we do things at the right time


And we'll use JUMPSPEED as a counter of the # repetitions.


Add in the highlighted code to your SPRITE TYPE 5 Event:



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

First, I've added in a spriteink command to colour the aliens with the value C (we'll add this in to the spawner Data table in a moment)


So, when this event first runs for a n alien sprite SettingA will be 0 (we'll need to add that in to Initialise Sprites in a moment)


This will then restore the data table (which means the next READ will be the very first value in the table). We will then cycle through the data until we find a value equal to 50 + the Level number (so, for level 1 we are looking for 51, for level 2 we look for 52 and so on).


I chose 50 since it's unlikely I'll need more than 50 directions (0-15 represent our 16 compass points.) but it leaves me room to add more later and means I could have over 200 movement patterns in this event, which should be more than enough.


Once we've found it, we will read in the next number to SETTINGB (we'll just use 0) and we will then set SettingA to 1 so that we don't restore the data each cycle.


It's important to recognise that each sprite always knows how far it has read through the data table, unless we RESTORE, at which point it goes back to the start.


Now that SettingA is 1, we will READ in the actual DIRECTION number and the number of REPETITIONS required into SETTINGB, we then set settingA to 2 to prevent this running again until all repetitions of the movement direction have been performed..



Note that I've also put some Boundary checking in place (not very efficiently, we'll improve it later) this will remove any aliens that travel off screen.


Finally, we have our DATA table, at the moment I have just replicated our original two movement pattern down and veer right, and down and veer left.



OK, before we test it, we have a couple more tasks to complete.


MENU: 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

Next, we'll update the Spawner Event 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				; 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

Here I have added a new value to each data set and split the two levels onto lines of their own to make it easier to read, the new (9th) value is the one that will be read into C.


I think we are ready to test!, let's build this bad boy!




Yeah! look at them fly!

OK, now let's have some fun, and create some new patterns to the DATA table in sprite type 5, be sure to start each pattern with 200+Level# followed by a zero and then your pairs of DIRECTION # and Repetition #


Try these for starters, then make up your own:


Replace the DATA table in your Alien event (Sprite Type 5) with:



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

And replace your Spawner Data table (Sprite Type 7) with:



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 

Now that we have 6 attack waves / levels you 'll need to update this line in your spawner event

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

to:

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

Save your game, then let's build it and shoot some aliens!!





Cool! feel free to experiment and create lots more attack patterns!


However, its about time we gave the aliens some weapons of their own, building on the framework we have already created and using some of the tricks we've learnt, we should be able to add lots more variety to the game.


NEXT: Part 9: The Aliens Fight Back!





0 views0 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