In the final (for now, at least) entry in this series, we are going to pull everything together into a playable “Shoot the Invaders from Space” game that has keyboard and joystick control, killable enemies, moving bullets, and a scrolling star field backdrop …
Previous AMOS Basic Tutorials in this series:
- Loading images and configuring AMOS screens
- “Dual Playfield”
- Bobs and Sprites
- Maps and Scrolling
- Better Tile Scrolling
- Animation & Scrolling with AMAL
The “Finished” Game
OK, it’s not exactly going to set Steam alight, and I am sure you can improve my code, but the game demonstrates enough that it is playable and has the major elements 🙂
Game Structure
To start, we are going to need a plan of attack.
In most games there will be a structure something like this:
- Load
- Show the start screen
- Do the setup
- Get player input
- Move the enemies
- Anything collide?
- Player still alive?
- Update the screen
- Loop back to 4 or go on to end screen
- End screen
- Loop back to 2 or end
Some items might shuffle around and you might have extra stuff, but essentially we need to fulfill all of those tasks if we are going to get a playable game.
This is more than a straight list of instructions so we will definitely need to break the game down into procedures.
As a reminder, your procedures are set up like so:
Procedure Procname Statements End Proc
Once you have set up your procedures, you can call them just by using it’s name (in the above example it would be Procname).
Checking for our Sprite File
Previously we have just trusted that the sprites were there in the local directory. Instead we should check for the existence of the file:
' Load the sprites, ' but first we check the file is there If Exist("invaders4.abk") Load "invaders4.abk",1 ' Assuming our sprites loaded, get the colours Get Bob Palette ' Set some specific colours ' for the enemy bullet sprite Colour 17,$FF0 Colour 18,$FFF Colour 20,$FA0 Else ' If no sprite file, show an error Paper 0 : Cls : Pen 4 Print "Sprites not found" ' quit out End End If
Generating Bobs
As well as loading a sprite bank, we can generate bobs on the fly.
Let’s make a “scrolling” background of a star field!
' Set up starfield For Y=1 To 200 Step 2 Plot Rnd(320),Y,SC(Rnd(6)) Next Y ' Get a bob for the stars Get Bob 0,10,0,0 To 320,200 ' Blank the screen Ink 0 : Bar 0,0 To 320,200
Animating the Background and Bullets
Both our star field and the player/enemy fire work the same way:
' Enemy and player fire ' One set to move down, ' other upwards _ZAP$="L: M 0,200,50; J L;" _PFIRE$="L: M 0,-200,50; J L;" Amal 5,_ZAP$ Amal 6,_PFIRE$ ' Starfield "scrolling" Amal 10,"L: Let Y=0; M 0,-200,200; J L;" Amal 11,"L: Let Y=200; M 0,-200,200; J L;"
The main difference is the bullets will only need to move all the way up or down the screen; their start positions reset when next fired, whereas in the “scrolling” bobs we loop round and round so there are always stars on screen.
One bob starts at 0 and the other at 200, and when they have moved 200 pixels they reset positions.
Reading the Joystick or Gamepad
Up to now we have used just keyboard control, either with Inkey$ or Key State. Here we have a simple way to also grab the joystick/gamepad control (in port 1 in this case)
' Get the player movement Procedure _PLAYER_INPUT ' What key was pressed? PRESSED$=Inkey$ ' If cursor left or right then move player If PRESSED$="o" and PLYER_X>0 PLYER_X=PLYER_X-4 End If If PRESSED$="p" and PLYER_X<290 PLYER_X=PLYER_X+4 End If ' If joystick left or right then move player If(Joy(1)=4 or Joy(1)=20) and PLYER_X>0 PLYER_X=PLYER_X-4 End If If(Joy(1)=8 or Joy(1)=24) and PLYER_X<290 PLYER_X=PLYER_X+4 End If ' Fire button If(Joy(1)>10 or PRESSED$=" ") and Y Bob(5)=<0 Bob 5,X Bob(4)+7,Y Bob(4)-16,8 Amal On 6 Shoot End If End Proc
Collision Detection
We need to know when a collision happens, either detecting the player bob bullet or the enemy sprite bullet. AMOS has a couple of easy to use features for detecting this.
' Did anything collide? Procedure _CHECK_COLLISIONS ' Make sure win/lose is zero _YOU_WIN=0 _YOU_DEAD=0 ' Any enemies drop below the player? ' if the enemies get past player then ' player loses If Y Bob(0)>160 or Y Bob(1)>160 or Y Bob(2)>160 or Y Bob(3)>160 Boom Sprite 1,X Hard(-100),Y Hard(220),5 Bob 5,320,0,8 _YOU_DEAD=1 _YOU_WIN=0 _KILLS=0 ' Did the player get hit? Else If Spritebob Col(1,4 To 4) ' Explosion sound Boom ' Move the bullets offscreen Sprite 1,X Hard(-100),Y Hard(220),5 Bob 5,320,0,8 ' reduce player's lives _LIVES=_LIVES-1 ' if out of lives they lose! If _LIVES=0 _YOU_DEAD=1 _YOU_WIN=0 _KILLS=0 End If End If ' Check if any enemies got hit For _THIS_ONE=0 To 3 ' Determine which was killed If Bob Col(5,_THIS_ONE To _THIS_ONE) ' The one killed was this one _KILLED=_THIS_ONE ' Increment player kills _KILLS=_KILLS+1 ' Turn off killed enemy Amal Off _KILLED+1 Bob 5,319,0,8 Bob _KILLED,-32,20,1 ' Make sound effect Boom ' Did they win? If _KILLS=4 ' You won! Pass go, collect points _YOU_WIN=1 _YOU_DEAD=0 Exit End If ' Exit the loop, we know our loser Exit End If ' Move on to the next enemy Next _THIS_ONE End Proc
Putting it all Together
' Global variables Global PLYER_X,PLYER_Y,_YOU_WIN,_YOU_DEAD,_KILLS,_KILLED,_LIVES ' Information screen Screen Open 1,320,200,16,Lowres Flash Off : Curs Off : Hide ' Game screen Screen Open 0,320,200,16,Lowres Flash Off : Curs Off : Hide Paper 0 Cls ' Load the sprites, ' but first we check the file is there If Exist("invaders4.abk") Load "invaders4.abk",1 ' Assuming our sprites loaded, get the colours Get Bob Palette ' Set some specific colours ' for the enemy bullet sprite Colour 17,$FF0 Colour 18,$FFF Colour 20,$FA0 Else ' If no sprite file, show an error Paper 0 : Cls : Pen 4 Print "Sprites not found" ' quit out End End If ' Set up smooth moves Double Buffer Autoback 1 ' Selected star colours Dim SC(6) SC(0)=6 SC(1)=7 SC(2)=8 SC(3)=9 SC(4)=13 SC(5)=14 SC(6)=15 ' Set up starfield For Y=1 To 200 Step 2 Plot Rnd(320),Y,SC(Rnd(6)) Next Y ' Get a bob for the stars Get Bob 0,10,0,0 To 320,200 ' Blank the screen Ink 0 : Bar 0,0 To 320,200 ' Initialize all values ' to their defaults Procedure _INIT ' These values control program flow ' for example if you won or lost _KILLS=0 _YOU_WIN=0 _YOU_DEAD=0 _LIVES=3 ' Set the screen to blank Paper 0 Pen 4 Cls 0 ' The sprite will be the enemy fire ' It needs a mask so collision detection ' can work and hotspot is where the x/y ' is counted from 'Amal Off Sprite 1,X Hard(0),Y Hard(200),5 Hot Spot 5,8,8 Make Mask 5 ' Starfield (because they ARE the background ' we tell it not to bother replacing the background) Bob 10,0,0,10 Set Bob 10,-1,1, Bob 11,0,200,10 Set Bob 11,-1,1, Limit Bob 10,0,0 To 320,160 Limit Bob 11,0,0 To 320,160 Priority Reverse On ' Add our enemy and player bobs Bob 0,0,40,1 Bob 1,40,40,1 Bob 2,80,40,1 Bob 3,120,40,1 PLYER_X=160 PLYER_Y=160 Bob 4,160,160,7 Bob 5,320,5,8 ' Animation channels Channel 1 To Bob 0 Channel 2 To Bob 1 Channel 3 To Bob 2 Channel 4 To Bob 3 Channel 5 To Sprite 1 Channel 6 To Bob 5 Channel 10 To Bob 10 Channel 11 To Bob 11 ' Animation and movement scripts A1$="Anim 0,(1,20)(2,20)(3,20)(4,20)(3,20)(2,20)" A2$="Label:" A3$="M 200,0,280;M 0,32,80;M -200,0,280; M 0,32,80;" A4$="Jump Label" A$=A1$+A2$+A3$+A4$ ' 4 enemies Amal 1,A$ Amal 2,A$ Amal 3,A$ Amal 4,A$ ' Enemy and player fire ' One set to move down, ' other upwards _ZAP$="L: M 0,200,50; J L;" _PFIRE$="L: M 0,-200,50; J L;" Amal 5,_ZAP$ Amal 6,_PFIRE$ ' Starfield "scrolling" Amal 10,"L: Let Y=0; M 0,-200,200; J L;" Amal 11,"L: Let Y=200; M 0,-200,200; J L;" ' Start animating Amal On End Proc ' Information screens ' in an actual game they would ' have graphics and stuff! Procedure _DO_SCREEN ' Set the info screen as the ' visible screen Screen 1 Screen To Front 1 Sprite Off Amal Off ' Set the message to blank MESS$="" ' Which message to display? If _YOU_WIN=1 MESS$="YOU WON. YAY." End If If _YOU_DEAD=1 MESS$="YOU DIED. SORRY." End If If _YOU_WIN=0 and _YOU_DEAD=0 MESS$="Alien types are invading. From Space!" End If _YOU_WIN=0 _YOU_DEAD=0 _KILLS=0 Paper 0 Pen 4 Cls Clear Key ' This loop makes the text ' change colour real fast Repeat ' Wait for screen refresh Wait Vbl ' Text to random colour Pen Rnd(8) Locate 10,5 Centre MESS$ Locate 10,15 Centre "Press Fire/Space to continue" Until Inkey$=" " or Joy(1)>10 ' After a keypress, switch ' to the game screen Screen 0 Screen To Front 0 End Proc ' In-Game kills and lives stats Procedure _UPDATE_HUD Locate 5,0 Print "KILLS: ",_KILLS," LIVES: ",_LIVES End Proc ' Get the player movement Procedure _PLAYER_INPUT ' What key was pressed? PRESSED$=Inkey$ ' If cursor left or right then move player If PRESSED$="o" and PLYER_X>0 PLYER_X=PLYER_X-4 End If If PRESSED$="p" and PLYER_X<290 PLYER_X=PLYER_X+4 End If ' If joystick left or right then move player If(Joy(1)=4 or Joy(1)=20) and PLYER_X>0 PLYER_X=PLYER_X-4 End If If(Joy(1)=8 or Joy(1)=24) and PLYER_X<290 PLYER_X=PLYER_X+4 End If ' Fire button If(Joy(1)>10 or PRESSED$=" ") and Y Bob(5)=<0 Bob 5,X Bob(4)+7,Y Bob(4)-16,8 Amal On 6 Shoot End If End Proc ' Did anything collide? Procedure _CHECK_COLLISIONS ' Make sure win/lose is zero _YOU_WIN=0 _YOU_DEAD=0 ' Any enemies drop below the player? ' if the enemies get past player then ' player loses If Y Bob(0)>160 or Y Bob(1)>160 or Y Bob(2)>160 or Y Bob(3)>160 Boom Sprite 1,X Hard(-100),Y Hard(220),5 Bob 5,320,0,8 _YOU_DEAD=1 _YOU_WIN=0 _KILLS=0 ' Did the player get hit? Else If Spritebob Col(1,4 To 4) ' Explosion sound Boom ' Move the bullets offscreen Sprite 1,X Hard(-100),Y Hard(220),5 Bob 5,320,0,8 ' reduce player's lives _LIVES=_LIVES-1 ' if out of lives they lose! If _LIVES=0 _YOU_DEAD=1 _YOU_WIN=0 _KILLS=0 End If End If ' Check if any enemies got hit For _THIS_ONE=0 To 3 ' Determine which was killed If Bob Col(5,_THIS_ONE To _THIS_ONE) ' The one killed was this one _KILLED=_THIS_ONE ' Increment player kills _KILLS=_KILLS+1 ' Turn off killed enemy Amal Off _KILLED+1 Bob 5,319,0,8 Bob _KILLED,-32,20,1 ' Make sound effect Boom ' Did they win? If _KILLS=4 ' You won! Pass go, collect points _YOU_WIN=1 _YOU_DEAD=0 Exit End If ' Exit the loop, we know our loser Exit End If ' Move on to the next enemy Next _THIS_ONE End Proc ' Make sure win/lose info is reset _YOU_WIN=0 _YOU_DEAD=0 ' Show welcome screen _DO_SCREEN ' Start of the infinite loop Do ' Set everything up ' with default values _INIT ' Game loop Repeat ' Turn off sprite drawing temporarily Bob Update Off Sprite Update Off ' Update the screen info _UPDATE_HUD ' Anything collided? _CHECK_COLLISIONS ' Update player movement _PLAYER_INPUT Bob 4,PLYER_X,PLYER_Y,7 ' If enemy fiire goes past the player .. If Y Sprite(1)>Y Hard(160) ' Choose a random enemy _SHOOTER=Rnd(3) ' If the enemy is on screen .. If X Bob(_SHOOTER)>0 ' Enemy shoots! Sprite 1,X Hard(X Bob(_SHOOTER)+8),Y Hard(Y Bob(_SHOOTER)+32),5 Amal On 5 End If End If ' Update sprite and bob drawing Bob Update On Sprite Update On Wait Vbl ' Keep looping until you win/lose Until _YOU_WIN=1 or _YOU_DEAD=1 ' Display the information screen _DO_SCREEN ' Outside loop goes on indefinitely Loop
Bonus: Play in your browser!

Wait, there’s more!
If you are running Chrome, you can play the AOZ.studio version of the game in your web browser!
AOZ is still in beta development, so it’s not fully ready, but eventually you will be able to take your Amiga AMOS knowledge and build cross-platform games for everything from Windows/Mac/Linux through to iOS and Android.
Find out more at AOZ.Studio