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 …
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 🙂
For legal reasons it is in no way inspired by any other classic arcade game that you might have seen, played, imagined, or heard about.
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