Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407

Dependencies:   Joystick N5110 SDFileSystem mbed

Revision:
5:34855f712350
Parent:
4:a99953ef9e42
Child:
6:89d4a7f7588b
diff -r a99953ef9e42 -r 34855f712350 main.cpp
--- a/main.cpp	Thu Mar 31 16:03:26 2016 +0000
+++ b/main.cpp	Wed Apr 27 00:19:52 2016 +0000
@@ -5,6 +5,7 @@
 Week 20 - Changed to space invaders as constrained too much by screen resolution
         - Core cannon is drawn and can move, enemies are visible and they switch between states every second
 Week 21 - Begun to set up barriers
+Easter  - Barriers work, invader and player can shoot. Begun setting up menus
 */
 #include "mbed.h"
 #include "N5110.h"
@@ -13,46 +14,46 @@
 #define LEFT 0
 #define RIGHT 1
 
-//Preprocessor for screen map
-/*
-#define EMPTY 0
-#define CANNON 1
-#define SMALL 2
-#define MEDIUM 3
-#define LARGE 4
-#define BARRIER 5
-#define UFO 6
-#define CANNON_SHOT 7
-*/
-
 //Joystick Class
 class Joystick
 {
 public:
+    //Constructor
     Joystick(PinName x_axis_pin, PinName y_axis_pin, PinName button_pin) {
-        //Dynamically allocates the pins
+        //Dynamically allocates the pins and button debounce ticker
         x_axis_ = new AnalogIn(x_axis_pin);
         y_axis_ = new AnalogIn(y_axis_pin);
         button_ = new InterruptIn(button_pin);
+        button_debounce_ = new Timeout();
+    }
+
+    //Deconstructor
+    ~Joystick() {
+        //Clears all dynamically allocated memory
+        delete x_axis_;
+        delete y_axis_;
+        delete button_;
+        delete button_debounce_;
     }
 
     //Initalises the Joystick
     //Sets up the ISRs and grabs the offsets for each axis
     void init() {
         //Sets up the button ISR
-        button_->mode(PullUp);
-        button_->fall(this, &Joystick::button_isr);
+        button_->mode(PullDown);
+        button_->rise(this, &Joystick::button_isr);
 
         //Initalises the vairables and flags
         x_offset_ = 0;
         y_offset_ = 0;
-        g_button_flag_ = 0;
+        g_button_flag_ = false;
+        g_button_debounce_flag_ = false;
 
         //Samples the joystick 5 times and takes an average to get the offset
         float x_sum = 0;
         float y_sum = 0;
 
-        for (int i = 0; i < 5; i++) {
+        for (int i = 0; i < 5; ++i) {
             x_sum += x_axis_->read();
             y_sum += y_axis_->read();
         }
@@ -66,7 +67,7 @@
 
         float x_sum = 0;
 
-        for (int i = 0; i < 5; i++) {
+        for (int i = 0; i < 5; ++i) {
             x_sum += x_axis_->read();
         }
 
@@ -86,7 +87,7 @@
 
         float y_sum = 0;
 
-        for (int i = 0; i < 5; i++) {
+        for (int i = 0; i < 5; ++i) {
             y_sum += y_axis_->read();
         }
 
@@ -114,7 +115,18 @@
 private:
     //Button ISR Method
     void button_isr() {
-        g_button_flag_ = 1;
+        if (!g_button_debounce_flag_) {
+            g_button_flag_ = true;
+            g_button_debounce_flag_ = true;
+
+            //Sets up the debounce ticker
+            button_debounce_->attach(this, &Joystick::button_debounce_isr, 0.2);
+        }
+    }
+
+    //Button debounce ISR method
+    void button_debounce_isr() {
+        g_button_debounce_flag_ = false;
     }
 
 private:
@@ -123,12 +135,16 @@
     AnalogIn* y_axis_;
     InterruptIn* button_;
 
+    //Ticker to prevent joystick button bounce
+    Timeout* button_debounce_;
+
     //Stores X and Y offsets
     float x_offset_;
     float y_offset_;
 
     //Stores interrupt flags
-    volatile int g_button_flag_;
+    volatile bool g_button_flag_;
+    volatile bool g_button_debounce_flag_;
 };
 
 // K64F on-board LEDs
@@ -144,7 +160,7 @@
 Serial pc(USBTX,USBRX);
 
 //Joystick
-Joystick joystick(PTB2, PTB3, PTB11);
+Joystick joystick(PTB3, PTB2, PTB11);
 
 //Shoot button
 InterruptIn shoot_button(PTB18);
@@ -152,10 +168,19 @@
 //LCD object
 //         VCC,    SCE,   RST,   D/C,   MOSI,  SCLK,   LED
 N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);
-Ticker update_screen;
 
-//Map holding pixel data of screen
-int screen_map[84][48];
+//Tickers
+Ticker update_screen;
+Ticker move_joystick;
+Ticker move_cannon_missile;
+Ticker move_enemies;
+Ticker move_invader_normal_missile[2];
+
+//Timeout
+Timeout joystick_cursor_regulator; //Stops the cursor from jumping
+
+//Buffer holding pixel data of screen with point representations
+int screen_buffer[84][48];
 const int empty_pixel = 0;
 const int cannon_pixel = 1;
 const int first_barrier_pixel = 2;
@@ -163,12 +188,45 @@
 const int first_medium_invader_pixel = 10;
 const int first_small_invader_pixel = 15;
 const int ufo_pixel = 20;
-const int cannon_shot_pixel = 21;
+const int cannon_missile_pixel = 21;
+const int invader_normal_missile_pixel = 22;
 
-//Ship bit-map and location
+//Booleans
+//Invader related bools
+bool invaders_in_state2 = true;
+bool invader_direction = RIGHT;
+//Cannon missile bool
+bool cannon_missile_on_screen = false;
+
+//Integers
+int score = 0; //Stores the score
+int fsm_state = 0; //Stores the state for menu fsm's
+int cursor_y_pos = 0; //Stores the cursor position
+//Cannon related integers
 int cannon_xpos = 24;
 const int cannon_ypos = 43;
-Ticker move_cannon;
+int number_of_lives = 3;
+//Cannon missile related integers
+int cannon_missile_x_pos = 28;
+int cannon_missile_y_pos = 40;
+//Invader related integers 
+int no_of_alive_invaders = 15;
+//Invader missile related integers
+int invader_strong_missile_x_pos;
+int invader_strong_missile_y_pos;
+
+//Floats
+float ticker_period = 1; //Stores the period of the invader move ticker
+
+//Enums
+enum Status {dead, dying, alive}; //Contains the status of invaders
+enum Invader {small, medium, large, none}; //Contains the type of invader passed into
+//Contains the current state of the game
+enum GameState {menu, game, paused, save, load};
+GameState game_state = menu;
+
+//Bit-maps
+//Cannon bit-map
 const bool cannon_bitmap[5][9] = {
     {0, 0, 0, 0, 1, 0, 0, 0, 0},
     {0, 0, 0, 1, 1, 1, 0, 0, 0},
@@ -176,32 +234,8 @@
     {1, 1, 1, 1, 1, 1, 1, 1, 1},
     {1, 1, 1, 1, 1, 1, 1, 1, 1}
 };
-
-Ticker move_cannon_shot;
-bool cannon_shot_on_screen = false;
-int cannon_shot_x_pos = 28;
-int cannon_shot_y_pos = 40;
-bool game_over = false;
-
-//Enemies
-Ticker move_enemies;
-bool invaders_in_state2 = true;
-bool invader_direction = RIGHT;
-//Struct to store enemy data
-struct Invaders {
-    int x_pos;
-    int y_pos;
-    bool is_alive;
-} small_invader[5], medium_invader[5], large_invader[5];
-int right_column_alive = 4;
-int left_column_alive = 0;
-enum LowestInvaderRow {small, medium, large};
-LowestInvaderRow lowest_invader_row_alive = large;
-//Limits the first invader can travel
-int minimum_invader_x_pos = 0;
-int maximum_invader_x_pos = 20;
 //Bitmaps for small invaders
-const bool small_invader_bitmap_1[6][8] = {
+const bool small_invader_bitmap_1[6][8] = { //First state
     {0, 0, 0, 1, 1, 0, 0, 0},
     {0, 1, 1, 1, 1, 1, 1, 0},
     {1, 1, 0, 1, 1, 0, 1, 1},
@@ -209,8 +243,7 @@
     {0, 1, 0, 1, 1, 0, 1, 0},
     {1, 0, 1, 0, 0, 1, 0, 1}
 };
-
-const bool small_invader_bitmap_2[6][8] = {
+const bool small_invader_bitmap_2[6][8] = { //Second state
     {0, 0, 0, 1, 1, 0, 0, 0},
     {0, 1, 1, 1, 1, 1, 1, 0},
     {1, 1, 0, 1, 1, 0, 1, 1},
@@ -219,7 +252,7 @@
     {0, 1, 0, 0, 0, 0, 1, 0}
 };
 //Bitmaps for medium invaders
-const bool medium_invader_bitmap_1[6][10] = {
+const bool medium_invader_bitmap_1[6][10] = { //First state
     {1, 0, 0, 1, 0, 0, 1, 0, 0, 1},
     {1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
     {1, 1, 1, 0, 1, 1, 0, 1, 1, 1},
@@ -227,8 +260,7 @@
     {0, 0, 1, 0, 0, 0, 0, 1, 0, 0},
     {0, 1, 0, 0, 0, 0, 0, 0, 1, 0}
 };
-
-const bool medium_invader_bitmap_2[6][10] = {
+const bool medium_invader_bitmap_2[6][10] = { //Second state
     {0, 0, 0, 1, 0, 0, 1, 0, 0, 0},
     {0, 0, 1, 1, 1, 1, 1, 1, 0, 0},
     {0, 1, 1, 0, 1, 1, 0, 1, 1, 0},
@@ -237,7 +269,7 @@
     {0, 0, 0, 1, 1, 1, 1, 0, 0, 0}
 };
 //Bitmaps for large invaders
-const bool large_invader_bitmap_1[6][12] = {
+const bool large_invader_bitmap_1[6][12] = { //First state
     {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
     {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
     {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
@@ -245,8 +277,7 @@
     {0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0},
     {0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0}
 };
-
-const bool large_invader_bitmap_2[6][12] = {
+const bool large_invader_bitmap_2[6][12] = { //Second state
     {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
     {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
     {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
@@ -254,15 +285,27 @@
     {0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0},
     {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
 };
-
-//Barriers
-struct Barriers {
-    int x_pos;
-    int y_pos;
-    bool before_bitmap[8][14];
-    bool after_bitmap[8][14];
-} barrier[3];
-int no_of_barriers = 3;
+//Normal invader missile bitmap
+const bool invader_normal_missile_bitmap[4][3] = {
+    {0, 1, 0},
+    {1, 1, 1},
+    {0, 1, 0},
+    {0, 1, 0}
+};
+//Strong invader missile bitmap
+const bool invader_strong_missile_bitmap_1[4][3] = { //First state
+    {0, 0, 1},
+    {0, 1, 0},
+    {1, 0, 0},
+    {0, 1, 0}
+};
+const bool invader_strong_missile_bitmap_2[4][3] = { //Second state
+    {0, 1, 0},
+    {1, 0, 0},
+    {0, 1, 0},
+    {0, 1, 1}
+};
+//Barrier bitmap
 const bool barrier_bitmap[8][14] = {
     {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
     {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
@@ -273,8 +316,18 @@
     {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
     {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
 };
-
-//TEST FOR SPEC UFO
+//Cannon barrier damage bitmap
+const bool barrier_cannon_missile_damage_bitmap[3][3] = {
+    {0, 1, 0},
+    {1, 0, 0},
+    {1, 0, 1}
+};
+//Normal invader barrier damage bitmap
+const bool barrier_invader_normal_missile_damage_bitmap[2][3] = {
+    {1, 0, 1},
+    {0, 1, 0}
+};
+//UFO Bitmap
 const bool ufo_bitmap[5][14] = {
     {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
     {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
@@ -283,15 +336,46 @@
     {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}
 };
 
-int row_no = 5;
-int col_no = 14;
+//Structs
+//Contains invader data
+struct Invaders {
+    int x_pos;
+    int y_pos;
+    enum Status status;
+} small_invader[5], medium_invader[5], large_invader[5]; //Five of each invader
+//Contains data for Invader normal missiles
+struct InvaderNormalMissiles {
+    int x_pos;
+    int y_pos;
+    bool fired;
+} invader_normal_missile[2];
+//Contains data for barriers
+struct Barriers {
+    int x_pos;
+    int y_pos;
+    bool before_bitmap[8][14];
+    bool after_bitmap[8][14];
+} barrier[3];
+//FSM for paused menu
+struct FSMPaused {
+    GameState output;
+    int next_state[2];
+};
+FSMPaused fsm_paused[3] = {
+    {game, {1, 2}},
+    {save, {2, 0}},
+    {menu, {0, 1}}
+};
 
 //ISR Flags
 volatile bool g_update_screen_flag = true;
-volatile bool g_move_cannon_flag = true;
+volatile bool g_move_joystick_flag = true;
+volatile bool g_move_enemies_flag = true;
 volatile bool g_shoot_pressed_flag = false;
-volatile bool g_move_cannon_shot_flag = false;
-volatile bool g_move_enemies_flag = true;
+volatile bool g_move_cannon_missile_flag = false;
+volatile bool g_move_invader_normal_missile_flag[2] = {false, false};
+volatile bool g_cannon_hit_flag = false;
+volatile bool g_joystick_cursor_regulator_flag = false;
 
 // function prototypes
 // error function hangs flashing an LED
@@ -302,215 +386,158 @@
 void init_K64F();
 //Init shoot button
 void init_shoot();
+//Init Random Number Generator
+void init_rng();
 // Added functions
+void InitaliseGame();
+void Game();
+void UpdateScreen();
 void MoveCannon();
 void InitSmallInvaders();
 void ClearSmallInvaders();
+void ClearSingleSmallInvader(int invader_no);
 void DrawSmallInvaders();
+void DrawSingleSmallInvader(int invader_no);
+void InitMediumInvaders();
 void ClearMediumInvaders();
-void InitMediumInvaders();
+void ClearSingleMediumInvader(int invader_no);
 void DrawMediumInvaders();
+void DrawSingleMediumInvader(int invader_no);
 void InitLargeInvaders();
-void CLearLargeInvaders();
+void ClearLargeInvaders();
+void ClearSingleLargeInvader(int invader_no);
 void DrawLargeInvaders();
+void DrawSingleLargeInvader(int invader_no);
 void InitBarriers();
 void DrawBarriers();
-void ShiftInvaderXPositions();
-void ShiftInvaderYPositions(bool new_direction);
+void MoveInvaderXPositions();
+int CalculateInvaderLeftLimit();
+int CalculateInvaderRightLimit();
+void MoveInvadersLeft(int limit);
+void MoveInvadersRight(int limit);
+void MoveInvaderYPositions(bool new_direction);
+Invader CalculateInvaderYLimit();
+Invader LowestInvaderInColumn(int column);
+void FireCannonMissile();
+void MoveCannonMissile();
+void CollisionDetectionCannonMissile();
+int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]);
+void CannonMissileHitBarrier(int first_pixel, int row);
+void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile));
+void AttemptToFireInvaderNormalMissiles();
+void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader));
+void MoveInvaderNormalMissile(int missile_no);
+void CollisionDetectionInvaderNormalMissile(int missile_no);
+void DetachTickers();
+void AttachTickers();
 //void InitUFO();
 void DrawUFO();
-//void DrawEnemies(struct Invaders invader[], int no_of_invaders);
-
 //ISR's
 void update_screen_isr();
-void move_cannon_isr();
+void move_joystick_isr();
 void move_enemies_isr();
 void shoot_pressed_isr();
-void move_cannon_shot_isr();
+void move_cannon_missile_isr();
+void cannon_hit_isr();
+void joystick_cursor_regulator_isr();
+//Function pointer to move invader normal missile isr
+void (*move_invader_normal_missile_isr[2])();
+void move_invader_normal_missile_0_isr();
+void move_invader_normal_missile_1_isr();
 
-int down_count = 0;
+int row_no = 5;
+int col_no = 14;
 
 int main()
 {
+    //Wait for 2 seconds to allow power to settle
+    wait(1);
     //Initalises the board and perhiperals
     init_K64F();
     init_serial();
     init_shoot();
+    init_rng();
+    joystick.init();
     lcd.init();
     lcd.clear();
 
-    update_screen.attach(&update_screen_isr, 0.05);
-    move_cannon.attach(&move_cannon_isr, 0.05);
-    move_enemies.attach(&move_enemies_isr, 0.5);
+    //Configures the function pointer for the invaders normal missile
+    move_invader_normal_missile_isr[0] = &move_invader_normal_missile_0_isr;
+    move_invader_normal_missile_isr[1] = &move_invader_normal_missile_1_isr;
 
-    InitSmallInvaders();
-    InitMediumInvaders();
-    InitLargeInvaders();
-    InitBarriers();
-
-    lcd.refresh();
+    //Samples joystick every 0.05 second
+    move_joystick.attach(&move_joystick_isr, 0.05);
 
     while (true) {
-        //IF the game is over detach all the tickers
-        if (game_over) {
-            move_cannon.detach();
-            move_enemies.detach();
-
+        if (game_state == menu) { //Menu screen
             lcd.clear();
-            lcd.printString("Game Over", 1, 2);
-        } else {
-            //Updates pixels on the screen
-            if (g_update_screen_flag) {
-                g_update_screen_flag = false;
+            lcd.printString("Menu", 0, 1);
 
-                //Loops through the screen map and sets pixels on the LCD
-                for (int col = 0; col < 84; col++) {
-                    for (int row = 0; row < 48; row++) {
-                        if (screen_map[col][row]) {
-                            lcd.setPixel(col, row);
-                        } else {
-                            lcd.clearPixel(col, row);
-                        }
-                    }
-                }
+            if(joystick.get_button_flag()) {
+                joystick.set_button_flag(0);
+                
+                //Clears the screen buffer and initalises the game
+                memset(screen_buffer, 0, sizeof(screen_buffer));
+                no_of_alive_invaders = 15;
+                score = 0;
+                number_of_lives = 3;
+                InitSmallInvaders();
+                InitMediumInvaders();
+                InitLargeInvaders();
+                InitBarriers();
+
+                game_state = game;
             }
-            //Controls cannon movement
-            if (g_move_cannon_flag) {
-                g_move_cannon_flag = false;
-
-                MoveCannon();
-                DrawBarriers();
+        } else if (game_state == paused) { //Paused screen
+            //Prints paused and a line underneath
+            lcd.printString("Paused", 24, 0);
+            lcd.drawLine(0, 7, 83, 7, 2);
+            //Displays the current score
+            char buffer[14];
+            sprintf(buffer, "Score: %d", score);
+            lcd.printString(buffer, 0, 1);
+            //Displays the no of lives
+            sprintf(buffer, "Lives: %d", number_of_lives);
+            lcd.printString(buffer, 0, 2);
+            lcd.drawLine(0, 23, 83, 23, 2);
+            //Prints options on pause menu
+            lcd.printString("Resume", 10, 3);
+            lcd.printString("Save", 10, 4);
+            lcd.printString("Quit", 10, 5);
 
-                lcd.refresh();
-            }
-            //Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
-            if (g_shoot_pressed_flag) {
-                g_shoot_pressed_flag = false;
+            //Draws the cursor
+            cursor_y_pos = ((fsm_state+3)*8)+3; //Adds 3 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3
+            lcd.drawRect(64, cursor_y_pos, 2, 2, 1);
+
+            if (g_move_joystick_flag) {
+                g_move_joystick_flag = false;
 
-                if (!cannon_shot_on_screen) {
-                    cannon_shot_on_screen = true;
-                    
-                    pc.printf("Shot Fired\n");
-
-                    //Add 4 to cannon x_pos to get shot x_pos
-                    cannon_shot_x_pos = cannon_xpos + 4;
-                    cannon_shot_y_pos = 40;
-                    move_cannon_shot.attach(&move_cannon_shot_isr, 0.05);
+                //If the joystick is is pushed down half way clear the cursor and set the next state
+                if (joystick.GetYValue() < 0.25f) {
+                    //Clears the cursor
+                    lcd.drawRect(64, cursor_y_pos, 2, 2, 2);
+                    //Sets the new state
+                    fsm_state = fsm_paused[fsm_state].next_state[0];
+                } else if (joystick.GetYValue() > 0.75f) {
+                    //Clears the cursor
+                    lcd.drawRect(64, cursor_y_pos, 2, 2, 2);
+                    //Sets the new state
+                    fsm_state = fsm_paused[fsm_state].next_state[1];
                 }
             }
-            //Move the cannon's shot
-            if (g_move_cannon_shot_flag) {
-                g_move_cannon_shot_flag = false;
-
-                //Checks bullet will not go beyond the bounds of the screen map
-                if (cannon_shot_y_pos > -1) {
-                    //Loops throught the shot bitmap and clears the pixels in the screen map
-                    for (int row = 0; row < 3; row++) {
-                        //Clears the position where the bullet was
-                        screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = empty_pixel;
-                    }
-
-                    //Increments the shot going up the screen
-                    cannon_shot_y_pos--;
 
-                    //Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen map
-                    for (int row = 0; row < 3; row++) {
-                        int object_no;
-                        if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_small_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_small_invader_pixel + 5))
-                        {
-                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_small_invader_pixel;
-                            small_invader[object_no].is_alive = false;
-                            pc.printf("Small (%d) Hit\n", object_no);
-                            cannon_shot_on_screen = false;
-                            move_cannon_shot.detach();
-                            break;
-                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_medium_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_medium_invader_pixel + 5)) {
-                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_medium_invader_pixel;
-                            medium_invader[object_no].is_alive = false;
-                            pc.printf("Medium (%d) Hit\n", object_no);
-                            cannon_shot_on_screen = false;
-                            move_cannon_shot.detach();
-                            break;
-                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_large_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_large_invader_pixel + 5)) {
-                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_large_invader_pixel;
-                            large_invader[object_no].is_alive = false;
-                            pc.printf("Large (%d) Hit\n", object_no);
-                            cannon_shot_on_screen = false;
-                            move_cannon_shot.detach();
-                            break;
-                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_barrier_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_barrier_pixel + 3)) {
-                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_barrier_pixel;   
-                            pc.printf("Barrier (%d) Hit\n", object_no);
-                            cannon_shot_on_screen = false;
-                            move_cannon_shot.detach();
-                            break;
-                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] == ufo_pixel) {
-                            pc.printf("UFO Hit\n");
-                            cannon_shot_on_screen = false;
-                            move_cannon_shot.detach();
-                            break;
-                        } else {
-                            screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = cannon_shot_pixel;
-                        }
-                    }  
-                } else {
-                    //Loops throught the shot bitmap and clears the pixels in the screen map
-                    for (int row = 1; row < 3; row++) {
-                        //Clears the position where the bullet was
-                        screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = empty_pixel;
-                    }
-                    cannon_shot_on_screen = false;
-                }
+            if (g_shoot_pressed_flag) {
+                g_shoot_pressed_flag = false;
+                game_state = fsm_paused[fsm_state].output;
             }
-        }
-        //Controls enemy movement
-        if (g_move_enemies_flag) {
-            g_move_enemies_flag = false;
+            
+        } else if (game_state == game) { //Game screen
 
-            //Added stuff to move to function
-            //Checks which columns of invaders are alive on the right and left sides and changes the limits of the first invader
-            //MOVE TO COLLISION DETECTION WHEN IT'S DONE
-            //Checking the left side
-            for (int i = 0; i < 5; i++) {
-                if (small_invader[i].is_alive || medium_invader[i].is_alive || large_invader[i].is_alive) {
-                    left_column_alive = i;
-                    break;
-                }
-            }
-            minimum_invader_x_pos = 0 - left_column_alive*13;
-            //Checking the right side
-            for (int j = 4; j >= 0; j--) {
-                if (small_invader[j].is_alive || medium_invader[j].is_alive || large_invader[j].is_alive) {
-                    right_column_alive = j;
-                    break;
-                }
-            }
-            maximum_invader_x_pos = 72 - right_column_alive*13;
-
-            //End of block
-
-            //Clears the old bitmaps
-            ClearSmallInvaders();
-            ClearMediumInvaders();
-            CLearLargeInvaders();
-
-            ShiftInvaderXPositions();
-
-
-            DrawSmallInvaders();
-            DrawMediumInvaders();
-            DrawLargeInvaders();
-            //DrawUFO();
-
-            invaders_in_state2 = !invaders_in_state2;
-
-            lcd.refresh();
-
-            //TEST CODE
-
-            //END
+            AttachTickers();
+            Game();
         }
 
+        pc.printf("P: %d\n", g_shoot_pressed_flag);
         sleep();
     }
 }
@@ -526,7 +553,6 @@
     // resistors that are enabled by default using InterruptIn
     sw2.mode(PullNone);
     sw3.mode(PullNone);
-
 }
 
 void error()
@@ -545,11 +571,17 @@
     pc.baud(115200);
 }
 
+//Seeds the random number generator with noise from an analog in pin
+void init_rng()
+{
+    AnalogIn rng_seed(PTC10);
+    srand(floor(10000*rng_seed.read()));
+}
+
 void init_shoot()
 {
     shoot_button.mode(PullUp);
     shoot_button.fall(&shoot_pressed_isr);
-
 }
 
 void update_screen_isr()
@@ -557,29 +589,195 @@
     g_update_screen_flag = true;
 }
 
+void move_enemies_isr()
+{
+    g_move_enemies_flag = true;
+}
+
 void shoot_pressed_isr()
 {
     g_shoot_pressed_flag = true;
+    pc.printf("B\n");
+}
+
+void move_cannon_missile_isr()
+{
+    g_move_cannon_missile_flag = true;
+}
+
+void move_joystick_isr()
+{
+    //Always set the move flag in a game
+    if (game_state == game) {
+        g_move_joystick_flag = true;
+    } else if (!g_joystick_cursor_regulator_flag) {
+    //Only sets the flag if the regulator is not set
+        g_move_joystick_flag = true;
+        g_joystick_cursor_regulator_flag = true;
+
+        //Attachs a timeout to clear the regulator in 0.2s to prevent the cursor from behaving erratically
+        joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.125);
+    }
+}
+
+void joystick_cursor_regulator_isr() {
+    g_joystick_cursor_regulator_flag = false;
+}
+
+void move_invader_normal_missile_0_isr()
+{
+    g_move_invader_normal_missile_flag[0] = true;
+}
+
+void move_invader_normal_missile_1_isr()
+{
+    g_move_invader_normal_missile_flag[1] = true;
+}
+
+void cannon_hit_isr()
+{
+    g_cannon_hit_flag = false;
 }
 
-void move_cannon_shot_isr()
-{
-    g_move_cannon_shot_flag = true;
+void Game()
+{  
+    //Stays within the loop while the selected state is game
+    pc.printf("G: %d\n", g_shoot_pressed_flag);
+    while (game_state == game) {
+        //If the game is over detach all the tickers
+        if (number_of_lives == 0) {
+            DetachTickers();
+
+            lcd.clear();
+            lcd.printString("Game Over.", 1, 2);
+        } else if (no_of_alive_invaders == 0) { //If the player wins a round
+            //Resets the no of alive invaders
+            no_of_alive_invaders = 15;
+            //Detaches the enemy ticker while reinitalising invaders
+            move_enemies.detach();
+            //Reinitalises objects
+            InitSmallInvaders();
+            InitMediumInvaders();
+            InitLargeInvaders();
+            //Reattaches enemy ticker
+            move_enemies.attach(&move_enemies_isr, 1);
+        } else {
+            //Updates pixels on the screen
+            if (g_update_screen_flag) {
+                g_update_screen_flag = false;
+
+                UpdateScreen();
+            }
+
+            //Controls cannon movement
+            if (g_move_joystick_flag) {
+                g_move_joystick_flag = false;
+
+                MoveCannon();
+                DrawBarriers();
+            }
+
+            //Controls enemy movement
+            if (g_move_enemies_flag) {
+                g_move_enemies_flag = false;
+
+                //Increses the speed the invaders move
+                move_enemies.detach();
+                ticker_period = 0.1+(no_of_alive_invaders*0.06);
+                move_enemies.attach(&move_enemies_isr, ticker_period);
+
+                //Clears the old bitmaps
+                ClearSmallInvaders();
+                ClearMediumInvaders();
+                ClearLargeInvaders();
+
+                MoveInvaderXPositions();
+                //Switches the bitmap state
+                invaders_in_state2 = !invaders_in_state2;
+
+                //Draws the invaders
+                DrawSmallInvaders();
+                DrawMediumInvaders();
+                DrawLargeInvaders();
+
+                //Attemots to fire the invaders missiles
+                AttemptToFireInvaderNormalMissiles();
+            }
+
+            //Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
+            if (g_shoot_pressed_flag) {
+                g_shoot_pressed_flag = false;
+
+                if (!cannon_missile_on_screen) {
+                    FireCannonMissile();
+                }
+            }
+
+            //Move the cannon shot
+            if (g_move_cannon_missile_flag) {
+                g_move_cannon_missile_flag = false;
+
+                MoveCannonMissile();
+            }
+
+            //Moves the invaders 1st normal missile
+            if (g_move_invader_normal_missile_flag[0]) {
+                g_move_invader_normal_missile_flag[0] = false;
+
+                MoveInvaderNormalMissile(0);
+            }
+
+            //Moves the invaders 2nd normal missile
+            if (g_move_invader_normal_missile_flag[1]) {
+                g_move_invader_normal_missile_flag[1] = false;
+
+                MoveInvaderNormalMissile(1);
+            }
+
+            if (joystick.get_button_flag()) {
+                joystick.set_button_flag(0);
+
+                //Clears the screen
+                lcd.clear();
+
+                //Resets the fsm state to 0
+                fsm_state = 0;
+                
+                //Detach all game tickers
+                DetachTickers();
+                
+                game_state = paused;
+            }
+        }
+
+        sleep();
+    }
 }
 
-void move_cannon_isr()
+
+void UpdateScreen()
 {
-    g_move_cannon_flag = true;
+    //Loops through the screen buffer and sets pixels on the LCD
+    for (int col = 0; col < 84; ++col) {
+        for (int row = 0; row < 48; ++row) {
+            if (screen_buffer[col][row]) {
+                lcd.setPixel(col, row);
+            } else {
+                lcd.clearPixel(col, row);
+            }
+        }
+    }
+
+    lcd.refresh();
 }
 
 void MoveCannon()
 {
     //Clears the ship
-    for (int col = 0; col < 9; col++) {
-        for (int row = 0; row < 5; row++) {
+    for (int col = 0; col < 9; ++col) {
+        for (int row = 0; row < 5; ++row) {
             if(cannon_bitmap[row][col]) {
-                //lcd.clearPixel(cannon_xpos+col, cannon_ypos+row);
-                screen_map[cannon_xpos+col][cannon_ypos+row] = empty_pixel;
+                screen_buffer[cannon_xpos+col][cannon_ypos+row] = empty_pixel;
             }
         }
     }
@@ -598,80 +796,76 @@
     }
 
     //Redraws the ship
-    for (int col = 0; col < 9; col++) {
-        for (int row = 0; row < 5; row++) {
+    for (int col = 0; col < 9; ++col) {
+        for (int row = 0; row < 5; ++row) {
             if(cannon_bitmap[row][col]) {
-                //lcd.setPixel(cannon_xpos+col, cannon_ypos+row);
-                screen_map[cannon_xpos+col][cannon_ypos+row] = cannon_pixel;
+                screen_buffer[cannon_xpos+col][cannon_ypos+row] = cannon_pixel;
             }
         }
     }
 }
 
-void move_enemies_isr()
-{
-    g_move_enemies_flag = true;
-}
-
 //Sets the position and aliveness of the small invaders
 void InitSmallInvaders()
 {
-    for (int i = 0; i < 5; i++) {
-        small_invader[i].x_pos = 2+ (i*13);
+    for (int i = 0; i < 5; ++i) {
+        small_invader[i].x_pos = 2 + (i*13);
         small_invader[i].y_pos = 1;
-        small_invader[i].is_alive = true;
+        small_invader[i].status = alive;
     }
 }
 
+//Cycles through all the small invaders. If they're not already dead clear them
 void ClearSmallInvaders()
 {
-    for (int i = 0; i < 5; i++) {
-        if (!invaders_in_state2) {
-            for (int col = 0; col < 8; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(small_invader_bitmap_1[row][col] && small_invader[i].x_pos + col >= 0 && small_invader[i].x_pos + col < 84) {
-                        //lcd.clearPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
-                        screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = empty_pixel;
-                    }
+    for (int i = 0; i < 5; ++i) {
+        if (small_invader[i].status) {
+            ClearSingleSmallInvader(i);
+        }
+    }
+}
+
+//Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
+void ClearSingleSmallInvader(int invader_no)
+{
+    for (int col = 0; col < 8; ++col) {
+        for (int row = 0; row < 6; ++row) {
+            if (invaders_in_state2) {
+                if (small_invader_bitmap_1[row][col]) {
+                    screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel;
                 }
-            }
-        } else {
-            for (int col = 0; col < 8; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(small_invader_bitmap_2[row][col] && small_invader[i].x_pos + col >= 0 && small_invader[i].x_pos + col < 84) {
-                        //lcd.clearPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
-                        screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = empty_pixel;
-                    }
+            } else {
+                if (small_invader_bitmap_2[row][col]) {
+                    screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel;
                 }
             }
         }
     }
+
+    small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive;
 }
 
 void DrawSmallInvaders()
 {
-    //For each small invader clear and redraws them if they're alive
-    for (int i = 0; i < 5; i++) {
-        //Checks if the invader is alive
-        if (small_invader[i].is_alive) {
-            //Reads off the bitmap and sets the allowed pixels
+    for (int i = 0; i < 5; ++i) {
+        if (small_invader[i].status == alive) {
+            DrawSingleSmallInvader(i);
+        }
+    }
+}
+
+//Cycles through the the screen invader bitmap and sets the pixels in the buffer
+void DrawSingleSmallInvader(int invader_no)
+{
+    for (int col = 0; col < 8; ++col) {
+        for (int row = 0; row < 6; ++row) {
             if (invaders_in_state2) {
-                for (int col = 0; col < 8; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(small_invader_bitmap_1[row][col]) {
-                            //lcd.setPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
-                            screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = first_small_invader_pixel + i;
-                        }
-                    }
+                if (small_invader_bitmap_1[row][col]) {
+                    screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = first_small_invader_pixel + invader_no;
                 }
             } else {
-                for (int col = 0; col < 8; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(small_invader_bitmap_2[row][col]) {
-                            //lcd.setPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
-                            screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = first_small_invader_pixel + i;
-                        }
-                    }
+                if (small_invader_bitmap_2[row][col]) {
+                    screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = first_small_invader_pixel + invader_no;
                 }
             }
         }
@@ -681,62 +875,61 @@
 //Sets the position and aliveness of the medium invaders
 void InitMediumInvaders()
 {
-    for (int i = 0; i < 5; i++) {
+    for (int i = 0; i < 5; ++i) {
         medium_invader[i].x_pos = 1 + (i*13);
         medium_invader[i].y_pos = 8;
-        medium_invader[i].is_alive = true;
+        medium_invader[i].status = alive;
     }
 }
 
 void ClearMediumInvaders()
 {
-    for (int i = 0; i < 5; i++) {
-        if (!invaders_in_state2) {
-            for (int col = 0; col < 10; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(medium_invader_bitmap_1[row][col] && medium_invader[i].x_pos + col >= 0 && medium_invader[i].x_pos + col < 84) {
-                        //lcd.clearPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
-                        screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = empty_pixel;
-                    }
-                }
-            }
-        } else {
-            for (int col = 0; col < 10; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(medium_invader_bitmap_2[row][col] && medium_invader[i].x_pos + col >= 0 && medium_invader[i].x_pos + col < 84) {
-                        //lcd.clearPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
-                        screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = empty_pixel;
-                    }
-                }
-            }
+    for (int i = 0; i < 5; ++i) {
+        if (medium_invader[i].status) {
+            ClearSingleMediumInvader(i);
         }
     }
 }
 
+void ClearSingleMediumInvader(int invader_no)
+{
+    for (int col = 0; col < 10; ++col) {
+        for (int row = 0; row < 6; ++row) {
+            if (invaders_in_state2) {
+                if (medium_invader_bitmap_1[row][col]) {
+                    screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel;
+                }
+            } else {
+                if (medium_invader_bitmap_2[row][col]) {
+                    screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel;
+                }
+            }
+        }
+    }
+
+    medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive;
+}
+
 void DrawMediumInvaders()
 {
-    //For each small invader clear and redraws them if they're alive
-    for (int i = 0; i < 5; i++) {
-        //Checks if the invader is alive
-        if (medium_invader[i].is_alive) {
-            //Reads off the bitmap and sets the allowed pixels
+    for (int i = 0; i < 5; ++i) {
+        if (medium_invader[i].status == alive) {
+            DrawSingleMediumInvader(i);
+        }
+    }
+}
+
+void DrawSingleMediumInvader(int invader_no)
+{
+    for (int col = 0; col < 10; ++col) {
+        for (int row = 0; row < 6; ++row) {
             if (invaders_in_state2) {
-                for (int col = 0; col < 10; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(medium_invader_bitmap_1[row][col]) {
-                            //lcd.setPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
-                            screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = first_medium_invader_pixel + i;
-                        }
-                    }
+                if (medium_invader_bitmap_1[row][col]) {
+                    screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = first_medium_invader_pixel + invader_no;
                 }
             } else {
-                for (int col = 0; col < 10; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(medium_invader_bitmap_2[row][col]) {
-                            //lcd.setPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
-                            screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = first_medium_invader_pixel + i;
-                        }
-                    }
+                if (medium_invader_bitmap_2[row][col]) {
+                    screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = first_medium_invader_pixel + invader_no;
                 }
             }
         }
@@ -746,108 +939,71 @@
 //Sets the position and aliveness of the large invaders
 void InitLargeInvaders()
 {
-    for (int i = 0; i < 5; i++) {
+    for (int i = 0; i < 5; ++i) {
         large_invader[i].x_pos = 0 + (i*13);
         large_invader[i].y_pos = 15;
-        large_invader[i].is_alive = true;
+        large_invader[i].status = alive;
+    }
+}
+
+void ClearLargeInvaders()
+{
+    for (int i = 0; i < 5; ++i) {
+        if (large_invader[i].status) {
+            ClearSingleLargeInvader(i);
+        }
     }
 }
 
-void CLearLargeInvaders()
+//Loops through the large invader bitmap, if the pixel in the bitmap is set to 1, set the pixel in the buffer to 0
+void ClearSingleLargeInvader(int invader_no)
 {
-    for (int i = 0; i < 5; i++) {
-        //Reads off the bitmap and sets the allowed pixels
-        if (!invaders_in_state2) {
-            for (int col = 0; col < 12; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(large_invader_bitmap_1[row][col] && large_invader[i].x_pos + col >= 0 && large_invader[i].x_pos + col < 84) {
-                        ///lcd.clearPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                        screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = empty_pixel;
-                    }
+    for (int col = 0; col < 12; ++col) {
+        for (int row = 0; row < 6; ++row) {
+            if (invaders_in_state2) {
+                if (large_invader_bitmap_1[row][col]) {
+                    screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel;
+                }
+            } else {
+                if (large_invader_bitmap_2[row][col]) {
+                    screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel;
                 }
             }
-        } else {
-            for (int col = 0; col < 12; col++) {
-                for (int row = 0; row < 6; row++) {
-                    if(large_invader_bitmap_2[row][col] && large_invader[i].x_pos + col >= 0 && large_invader[i].x_pos + col < 84) {
-                        //lcd.clearPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                        screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = empty_pixel;
-                    }
+        }
+    }
+
+    large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive;
+}
+
+void DrawLargeInvaders()
+{
+    for (int i = 0; i < 5; ++i) {
+        if (large_invader[i].status == alive) {
+            DrawSingleLargeInvader(i);
+        }
+    }
+}
+
+void DrawSingleLargeInvader(int invader_no)
+{
+    for (int col = 0; col < 12; ++col) {
+        for (int row = 0; row < 6; ++row) {
+            if (invaders_in_state2) {
+                if (large_invader_bitmap_1[row][col]) {
+                    screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = first_large_invader_pixel + invader_no;
+                }
+            } else {
+                if (large_invader_bitmap_2[row][col]) {
+                    screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = first_large_invader_pixel + invader_no;
                 }
             }
         }
     }
 }
 
-void DrawLargeInvaders()
-{
-    //For each small invader clear and redraws them if they're alive
-    for (int i = 0; i < 5; i++) {
-        //Checks if the invader is alive
-        if (large_invader[i].is_alive) {
-            //Reads off the bitmap and sets the allowed pixels
-            if (invaders_in_state2) {
-                for (int col = 0; col < 12; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(large_invader_bitmap_1[row][col]) {
-                            //lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                            screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = first_large_invader_pixel + i;
-                        }
-                    }
-                }
-            } else {
-                for (int col = 0; col < 12; col++) {
-                    for (int row = 0; row < 6; row++) {
-                        if(large_invader_bitmap_2[row][col]) {
-                            //lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                            screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = first_large_invader_pixel + i;
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-/*
-void DrawInvaders(struct Invaders invader[], int no_of_invaders, bool bitmap[][])
-{
-    //For each small invader clear and redraws them if they're alive
-    for (int i = 0; i < no_of_invaders; i++) {
-        //Clears the enemy position
-        lcd.drawRect(invader[i].x_pos, invader[i].y_pos, 12, 6, 2);
-
-        //Checks if the invader is alive
-        if (invader[i].is_alive) {
-            //Reads off the bitmap and sets the allowed pixels
-            int col = 0;
-            int row = 0;
-            //Flips the bitmap everytime the function is called
-            if (invaders_in_state2) {
-                for (col = 0; col < 12; col++) {
-                    for (row = 0; row < 6; row++) {
-                        if(large_invader_bitmap_1[row][col]) {
-                            lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                        }
-                    }
-                }
-            } else {
-                for (col = 0; col < 12; col++) {
-                    for (row = 0; row < 6; row++) {
-                        if(large_invader_bitmap_2[row][col]) {
-                            lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-*/
-
-
 void InitBarriers()
 {
-    for (int i = 0; i < no_of_barriers; i++) {
+    for (int i = 0; i < 3; ++i) {
         barrier[i].x_pos = 10 + (i*25);
         barrier[i].y_pos = 33;
         //Copies the bitmap into the structs
@@ -859,16 +1015,14 @@
 void DrawBarriers()
 {
     //Clears the barrier and redraws it with damage applied
-    for (int i = 0; i < no_of_barriers; i++) {
-        for (int col = 0; col < 14; col++) {
-            for (int row = 0; row < 8; row++) {
+    for (int i = 0; i < 3; ++i) {
+        for (int col = 0; col < 14; ++col) {
+            for (int row = 0; row < 8; ++row) {
                 if (barrier[i].before_bitmap[row][col]) {
-                    //lcd.clearPixel(barrier[i].x_pos + col, barrier[i].y_pos + row);
-                    screen_map[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel;
+                    screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel;
                 }
                 if (barrier[i].after_bitmap[row][col]) {
-                    //lcd.setPixel(barrier[i].x_pos + col, barrier[i].y_pos + row);
-                    screen_map[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i;
+                    screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i;
                 }
             }
         }
@@ -877,57 +1031,124 @@
     }
 }
 
-void ShiftInvaderXPositions()
+void MoveInvaderXPositions()
 {
+    //Checks the left limit
+    int left_invader_limit = CalculateInvaderLeftLimit();
+
+    //Checking the right limit
+    int right_invader_limit = CalculateInvaderRightLimit();
+
+    //End of block
     if (invader_direction == RIGHT) {
+        MoveInvadersRight(right_invader_limit);
+    } else {
         //Checks the first large invader to see if it can travel anymore
-        if (large_invader[0].x_pos < maximum_invader_x_pos) {
-            for (int i = 0; i < 5; i++) {
-                small_invader[i].x_pos += 2;
-                medium_invader[i].x_pos += 2;
-                large_invader[i].x_pos += 2;
-            }
-        } else {
-            ShiftInvaderYPositions(LEFT);
+        MoveInvadersLeft(left_invader_limit);
+    }
+}
+
+int CalculateInvaderLeftLimit()
+{
+    for (int i = 0; i < 5; ++i) {
+        if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) {
+            return i;
+        }
+    }
+
+    //Sort gameover out stuff after
+    return 4;
+}
+
+int CalculateInvaderRightLimit()
+{
+    for (int i = 4; i >= 0; --i) {
+        if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) {
+            return i;
+        }
+    }
+
+    //Sort gameover stuff
+    return 0;
+}
+
+void MoveInvadersLeft(int limit)
+{
+    //Checks the first large invader to see if it can travel anymore
+    if (large_invader[limit].x_pos > 1) {
+        for (int i = 0; i < 5; ++i) {
+            small_invader[i].x_pos -= 2;
+            medium_invader[i].x_pos -= 2;
+            large_invader[i].x_pos -= 2;
         }
     } else {
-        //Checks the first large invader to see if it can travel anymore
-        if (large_invader[0].x_pos > minimum_invader_x_pos) {
-            for (int i = 0; i < 5; i++) {
-                small_invader[i].x_pos -= 2;
-                medium_invader[i].x_pos -= 2;
-                large_invader[i].x_pos -= 2;
-            }
-        } else {
-            ShiftInvaderYPositions(RIGHT);
-        }
+        //Shifts the Invaders down and passes in the new direction
+        MoveInvaderYPositions(RIGHT);
     }
 }
 
-void ShiftInvaderYPositions(bool new_direction)
+void MoveInvadersRight(int limit)
 {
-    //Checks to see which row of invaders are still alive to work out maximum y positions
-    if (large_invader[0].is_alive || large_invader[1].is_alive || large_invader[2].is_alive || large_invader[3].is_alive || large_invader[4].is_alive) {
-        lowest_invader_row_alive = large;
-    } else if (medium_invader[0].is_alive || medium_invader[1].is_alive || medium_invader[2].is_alive || medium_invader[3].is_alive || medium_invader[4].is_alive) {
-        lowest_invader_row_alive = medium;
+    //Checks the first large invader to see if it can travel anymore
+    if (large_invader[limit].x_pos < 71) {
+        for (int i = 0; i < 5; ++i) {
+            small_invader[i].x_pos += 2;
+            medium_invader[i].x_pos += 2;
+            large_invader[i].x_pos += 2;
+        }
     } else {
-        lowest_invader_row_alive = small;
+        //Shifts the Invaders down and passes in the new direction
+        MoveInvaderYPositions(LEFT);
     }
+}
+
+void MoveInvaderYPositions(bool new_direction)
+{
+    //Finds the invaders lower limit
+    Invader lowest_invader = CalculateInvaderYLimit();
+
+    //When moving down lowest_invader should not equal none
+    if (lowest_invader == none) {
+        error();
+    }
+
     //If an invader touches the bottom the game ends, otherwise the invaders descend
-    if (small_invader[0].y_pos < 39 - (7*lowest_invader_row_alive)) {
-        for (int i = 0; i < 5; i++) {
+    if (small_invader[0].y_pos < 33 - (7*lowest_invader)) {
+        for (int i = 0; i < 5; ++i) {
             small_invader[i].y_pos += 3;
             medium_invader[i].y_pos += 3;
             large_invader[i].y_pos += 3;
-            invader_direction = new_direction;
         }
+        invader_direction = new_direction;
+    } else {
+        number_of_lives = 0;
+    }
+}
+
+Invader CalculateInvaderYLimit()
+{
+    //Checks to see which row of invaders are still alive to work out maximum y positions
+    if (large_invader[0].status == alive || large_invader[1].status == alive || large_invader[2].status == alive || large_invader[3].status == alive || large_invader[4].status == alive) {
+        return large;
+    } else if (medium_invader[0].status == alive || medium_invader[1].status == alive || medium_invader[2].status == alive || medium_invader[3].status == alive || medium_invader[4].status == alive) {
+        return medium;
     } else {
-        game_over = true;
+        return small;
     }
+}
 
-    //TEST CODE
-    down_count++;
+//Queries the invaders on their status and returns the type of invader which is alive
+Invader LowestInvaderInColumn(int column)
+{
+    if (large_invader[column].status == alive) {
+        return large;
+    } else if (medium_invader[column].status == alive) {
+        return medium;
+    } else if (small_invader[column].status == alive) {
+        return small;
+    } else {
+        return none;
+    }
 }
 
 /*
@@ -942,12 +1163,283 @@
     //Draws the UFO
     int x_pos = 20;
     int y_pos = 25;
-    for (int col = 0; col < col_no; col++) {
-        for (int row = 0; row < row_no; row++) {
+    for (int col = 0; col < col_no; ++col) {
+        for (int row = 0; row < row_no; ++row) {
             if(ufo_bitmap[row][col]) {
-                //lcd.setPixel(x_pos + col, y_pos + row);
-                screen_map[x_pos + col][y_pos + row] = ufo_pixel;
+                screen_buffer[x_pos + col][y_pos + row] = ufo_pixel;
             }
         }
     }
+}
+
+void FireCannonMissile()
+{
+    cannon_missile_on_screen = true;
+
+    //Add 4 to cannon x_pos to get shot x_pos
+    cannon_missile_x_pos = cannon_xpos + 4;
+    cannon_missile_y_pos = 40;
+    move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
+}
+
+void MoveCannonMissile()
+{
+    //Checks bullet will not go beyond the bounds of the screen buffer
+    if (cannon_missile_y_pos > -1) {
+        //Loops throught the shot bitmap and clears the pixels in the screen buffer
+        for (int row = 0; row < 4; ++row) {
+            //Clears the position where the bullet was
+            screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
+        }
+
+        //Increments the shot going up the screen
+        --cannon_missile_y_pos;
+
+        //Checks to see if the shot will hit anything
+        CollisionDetectionCannonMissile();
+    } else {
+        //Loops throught the shot bitmap and clears the pixels in the screen buffer
+        for (int row = 1; row < 4; ++row) {
+            //Clears the position where the bullet was
+            screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
+        }
+
+        cannon_missile_on_screen = false;
+        move_cannon_missile.detach();
+    }
+}
+
+void MoveInvaderNormalMissile(int missile_no)
+{
+    //Checks missile will not exceed screen buffer
+    if (invader_normal_missile[missile_no].y_pos < 44) {
+        //Loops through the bitmap and clears the missile from the screen buffer
+        for (int col = 0; col < 3; ++col) {
+            for (int row = 0; row < 4; ++row) {
+                if (invader_normal_missile_bitmap[row][col]) {
+                    screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel;
+                }
+            }
+        }
+
+        //Increments the position of the missile
+        ++invader_normal_missile[missile_no].y_pos;
+
+        //Collision detection
+        CollisionDetectionInvaderNormalMissile(missile_no);
+
+    } else {
+        //Loops through the bitmap and clears the pixels still on the screen
+        for (int col = 0; col < 3; ++col) {
+            for (int row = 0; row < 4; ++row) {
+                if (invader_normal_missile_bitmap[row][col]) {
+                    screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel;
+                }
+            }
+        }
+
+        invader_normal_missile[missile_no].fired = false;
+        move_invader_normal_missile[missile_no].detach();
+    }
+}
+
+//Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer
+void CollisionDetectionCannonMissile()
+{
+    for (int row = 0; row < 4; ++row) {
+        int object_no;
+        if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_small_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_small_invader_pixel + 5)) { //Collides with a small invader
+            object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader);
+            ClearSingleSmallInvader(object_no);
+            score += 40;
+            break;
+        } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_medium_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_medium_invader_pixel + 5)) { //Collides with a medium invader
+            object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader);
+            ClearSingleMediumInvader(object_no);
+            score += 20;
+            break;
+        } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_large_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_large_invader_pixel + 5)) { //Collides with a large invader
+            object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader);
+            ClearSingleLargeInvader(object_no);
+            score += 10;
+            break;
+        } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_barrier_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_barrier_pixel + 3)) { //Collides with a barrier
+            CannonMissileHitBarrier(first_barrier_pixel, row);
+            DrawBarriers();
+            break;
+        } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] == ufo_pixel) { //Collides with a UFO
+            pc.printf("UFO Hit\n");
+            cannon_missile_on_screen = false;
+            move_cannon_missile.detach();
+            break;
+        } else {
+            screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = cannon_missile_pixel;
+        }
+    }
+}
+
+//Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer
+void CollisionDetectionInvaderNormalMissile(int missile_no)
+{
+    //Invader missile coordinates shifted to match centre bottom of bitmap
+    int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1;
+    int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3;
+    if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) {
+        //Decrements the number of lives, pauses the game for 2 seconds
+        //Marks the cannon as hit
+        g_cannon_hit_flag = true;
+        //Detaches all tickers
+        DetachTickers();
+        //Creates a Ticker object on the stack with a period of 2 seconds to pause the game for 2 seconds
+        Ticker cannon_hit;
+        cannon_hit.attach(&cannon_hit_isr, 2);
+        while (g_cannon_hit_flag) {
+            sleep();
+        }
+        cannon_hit.detach();
+        AttachTickers();
+        --number_of_lives;
+        invader_normal_missile[missile_no].fired = false;
+        move_invader_normal_missile[missile_no].detach();
+    } else if (screen_buffer[relative_x_pos][relative_y_pos] >= first_barrier_pixel && screen_buffer[relative_x_pos][relative_y_pos] < (first_barrier_pixel + 3)) {
+        //Finds barrier number
+        InvaderNormalMissileHitBarrier(first_barrier_pixel, invader_normal_missile[missile_no]);
+        invader_normal_missile[missile_no].fired = false;
+        move_invader_normal_missile[missile_no].detach();
+    } else {
+        for (int col = 0; col < 3; ++col) {
+            for (int row = 0; row < 4; ++row) {
+                if (invader_normal_missile_bitmap[row][col]) {
+                    screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = invader_normal_missile_pixel;
+                }
+            }
+        }
+    }
+}
+
+//Finds the invader number the shot hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen
+int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5])
+{
+    int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel;
+    invader[invader_no].status = dying;
+    cannon_missile_on_screen = false;
+    --no_of_alive_invaders;
+    move_cannon_missile.detach();
+
+    return invader_no;
+}
+
+//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
+void CannonMissileHitBarrier(int first_pixel, int row)
+{
+    int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel;
+    //Essentially inverse of barrier init
+    int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1;
+    int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; //Don't know why it's -1 and not -2
+    //Loops through the damage bitmap and modifies the barrier's after bitmap
+    for (int col = 0; col < 3; ++col) {
+        for (int row_bit = 0; row_bit < 3; ++row_bit) {
+            //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
+            if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) {
+                barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_cannon_missile_damage_bitmap[row_bit][col];
+            }
+        }
+    }
+    cannon_missile_on_screen = false;
+    move_cannon_missile.detach();
+}
+
+//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
+void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile))
+{
+    int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_pixel;
+    //Essentially inverse of barrier init
+    int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1;
+    int relative_y_pos = (missile.y_pos + 3) - 33;
+    //Loops through the damage bitmap and modifies the barrier's after bitmap
+    for (int col = 0; col < 3; ++col) {
+        for (int row_bit = 0; row_bit < 2; ++row_bit) {
+            //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
+            if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) {
+                barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col];
+            }
+        }
+    }
+}
+
+void AttemptToFireInvaderNormalMissiles()
+{
+    //Fires the normal missiles
+    //Loops through the 2 allowed missiles and if they're not on the screen, randomly fire
+    for (int i = 0; i < 2; ++i) {
+        if (!invader_normal_missile[i].fired) {
+            //If the random mumber is 1, fire a missile
+            //Higher chance when there are less invaders on the screen, up to a 1/3 chance
+            if ((rand() % (no_of_alive_invaders + 2)) == 1) {
+//            if ((rand() % 5) == 1) {
+                int fired_column;
+                int loop_limit = 0; //Stops loop from never ending
+                Invader missile_source;
+                do {
+                    fired_column = rand() % 5;
+                    missile_source = LowestInvaderInColumn(fired_column);
+                    ++loop_limit;
+                } while (missile_source == none && loop_limit < 10);
+
+                //Finds the centre point of the chosen invader and fires the missile
+                //If the loop limit is reached, the missile source will be none and the for loop will jump to the next iteration
+                if (missile_source == none) {
+                    continue;
+                } else if (missile_source == large) {
+                    FireNormalInvaderMissile(i, missile_source, large_invader[fired_column]);
+                } else if (missile_source == medium) {
+                    FireNormalInvaderMissile(i, missile_source, medium_invader[fired_column]);
+                } else {
+                    FireNormalInvaderMissile(i, missile_source, small_invader[fired_column]);
+                }
+            }
+        }
+    }
+}
+
+//Pass by reference to re
+void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader))
+{
+    //Finds the centre point of the chosen invader and fires the missile
+    //Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3
+    invader_normal_missile[missile_no].x_pos = invader.x_pos + (3 + source);
+    invader_normal_missile[missile_no].y_pos = invader.y_pos + 6;
+    invader_normal_missile[missile_no].fired = true;
+
+    //Uses a function pointer to attach the ticker
+    move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05);
+}
+
+void DetachTickers()
+{
+    update_screen.detach();
+    move_enemies.detach();
+    if (cannon_missile_on_screen) {
+        move_cannon_missile.detach();
+    }
+    for (int i = 0; i < 2; ++i) {
+        if (invader_normal_missile[i].fired) {
+            move_invader_normal_missile[i].detach();
+        }
+    }
+}
+
+void AttachTickers()
+{
+    update_screen.attach(&update_screen_isr, 0.05);
+    move_enemies.attach(&move_enemies_isr, ticker_period);
+
+    if (cannon_missile_on_screen) {
+        move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
+    }
+    for (int i = 0; i < 2; ++i) {
+        if (invader_normal_missile[i].fired) {
+            move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05);
+        }
+    }
 }
\ No newline at end of file