Updated Space Invaders on the mbed. Improved upon Michael Son's "Mbed Space Invaders" at https://os.mbed.com/users/michaeljson/notebook/mbed-space-invaders/.

Dependencies:   mbed wave_player mbed-rtos 4DGL-uLCD-SE SparkfunAnalogJoystick SDFileSystem LSM9DS1_Library_cal_updated

Fork of Two-PlayerSpaceInvaders by William Minix

test

Revision:
24:ea19c7e8a479
Parent:
23:56f6a12aaebd
Child:
25:17f2ec000357
diff -r 56f6a12aaebd -r ea19c7e8a479 main.cpp
--- a/main.cpp	Mon Apr 26 21:53:25 2021 +0000
+++ b/main.cpp	Wed Apr 28 01:10:03 2021 +0000
@@ -78,7 +78,7 @@
 //Nav_Switch myNav(p16, p10, p11, p9, p12); //pin order on Sparkfun breakout. move U from p13 to p16 so we can use another Serial to communicate with mbed
 DigitalIn pb(p20); // push button for player misisle fire
 Serial pc(USBTX, USBRX);
-Serial secondMbed(p13, p14);
+RawSerial secondMbed(p13, p14);
 PwmOut red(p21); // added to dim and brighten red LED -- Brice
 PwmOut green(p22); // added to dim and brighten green LED -- Brice
 PwmOut blue(p23); // added to dim and brighten blue LED -- Brice
@@ -115,10 +115,10 @@
 volatile int firing_col = 0;
 volatile int hit_player = 0;
 volatile bool lose = false;
-volatile int lives1 = 3;
-volatile int lives2 = 2;
-volatile int lives3 = 1;
-volatile int level = 1;
+volatile int lives1 = 3; // number of lives in level 1
+volatile int lives2 = 2; // number of lives in level 2
+volatile int lives3 = 1; // number of lives in level 3
+volatile int level = 1; // the level, number of lives/difficulty
 volatile bool game_menu = false;
 volatile bool begin_game = false;
 volatile bool gameover = false;
@@ -140,6 +140,8 @@
 // Intialize global player and enemy missile
 missile_t missile; // player missile
 missile_t enemy_missile; // enemy missile
+missile_t enemy_missile2; // first extra enemy missile for level 2 (medium difficulty)
+missile_t enemy_missile3; // second extra enemy missile for level 3 (hard difficulty) -- 3 missiles out at one time.
 
 // Array of enemy objects
 enemy_t * enemyArray[15];
@@ -229,17 +231,23 @@
     unsigned int start_barrier_y_pos = 95; 
     
     // First Row of Enemies
-    barrier_init(&barrier_1,start_x_pos,start_barrier_y_pos,GREEN); // initialize x-pos and y-pos and color of enemy
-    barrier_show(&barrier_1); // displays the enemy on uLCD
+    if (level == 1) {
+        barrier_init(&barrier_1,start_x_pos,start_barrier_y_pos,GREEN); // initialize x-pos and y-pos and color of enemy
+        barrier_show(&barrier_1); // displays the enemy on uLCD
+    }
     
     barrier_init(&barrier_2,start_x_pos+32,start_barrier_y_pos,GREEN);
     barrier_show(&barrier_2);
     
-    barrier_init(&barrier_3,start_x_pos+64,start_barrier_y_pos,GREEN);
-    barrier_show(&barrier_3);
+    if (level == 1 || level == 2) {
+        barrier_init(&barrier_3,start_x_pos+64,start_barrier_y_pos,GREEN);
+        barrier_show(&barrier_3);
+    }
     
-    barrier_init(&barrier_4,start_x_pos+96,start_barrier_y_pos,GREEN);
-    barrier_show(&barrier_4);
+    if (level == 1) {
+        barrier_init(&barrier_4,start_x_pos+96,start_barrier_y_pos,GREEN);
+        barrier_show(&barrier_4);
+    }
 }
 
 // Draws the player at the initial starting location
@@ -308,8 +316,17 @@
 
 // Checks if player is hit
 void check_player_hit()
-{    
-    hit_player = check_player(&player, &enemy_missile); // checks if the missile hits the player and returns 1 if hit, 0 if not hit
+{   
+    if (level == 1) {
+        // checks if the missile hits the player and returns 1 if hit, 0 if not hit for level 3
+        hit_player = check_player(&player, &enemy_missile);
+    } else if (level == 2) {
+        // checks if the missile hits the player and returns 1 if hit, 0 if not hit for level 3
+        hit_player = (check_player(&player, &enemy_missile) || check_player(&player, &enemy_missile2));
+    } else if (level == 3) {
+        // checks if the missile hits the player and returns 1 if hit, 0 if not hit for level 3
+        hit_player = (check_player(&player, &enemy_missile) || check_player(&player, &enemy_missile2) || check_player(&player, &enemy_missile3));
+    }
 }
 
 // Randomly selects an enemy to fire and updates the position of where the missile will fire from
@@ -341,6 +358,64 @@
         enemy_missile.missile_blk_y = enemyArray[firing_col]->enemy_blk_y + enemyArray[firing_col]->enemy_height + 1;
         enemy_missile.status = ENEMY_MISSILE_ACTIVE;
     }
+    // second random missile for level 2   
+    if (level == 2 || level == 3) {
+        firing_col = rand() % 5; // selects a random column
+    
+        // first checks if the 3rd row closest to the player is alive
+        if (enemyArray[firing_col+10]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile2.missile_blk_x = enemyArray[firing_col+10]->enemy_blk_x + (enemyArray[firing_col+10]->enemy_width/2);
+            enemy_missile2.missile_blk_y = enemyArray[firing_col+10]->enemy_blk_y + enemyArray[firing_col+10]->enemy_height + 1;
+            enemy_missile2.status = ENEMY_MISSILE_ACTIVE; // sets the enemy missile as active
+        }
+        // if enemy at 3rd row is dead, checks the enemy in the 2nd row
+        else if (enemyArray[firing_col+5]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile2.missile_blk_x = enemyArray[firing_col+5]->enemy_blk_x + (enemyArray[firing_col+5]->enemy_width/2);
+            enemy_missile2.missile_blk_y = enemyArray[firing_col+5]->enemy_blk_y + enemyArray[firing_col+5]->enemy_height + 1;
+            enemy_missile2.status = ENEMY_MISSILE_ACTIVE;
+        }
+        // if enemy at 2nd and 3rd row is dead, checks the enemy in the 1st row
+        else if (enemyArray[firing_col]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile2.missile_blk_x = enemyArray[firing_col]->enemy_blk_x + (enemyArray[firing_col]->enemy_width/2);
+            enemy_missile2.missile_blk_y = enemyArray[firing_col]->enemy_blk_y + enemyArray[firing_col]->enemy_height + 1;
+            enemy_missile2.status = ENEMY_MISSILE_ACTIVE;
+        }
+    }
+    // 3rd random missile for level 3
+    if (level == 3) {
+        firing_col = rand() % 5; // selects a random column
+    
+        // first checks if the 3rd row closest to the player is alive
+        if (enemyArray[firing_col+10]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile3.missile_blk_x = enemyArray[firing_col+10]->enemy_blk_x + (enemyArray[firing_col+10]->enemy_width/2);
+            enemy_missile3.missile_blk_y = enemyArray[firing_col+10]->enemy_blk_y + enemyArray[firing_col+10]->enemy_height + 1;
+            enemy_missile3.status = ENEMY_MISSILE_ACTIVE; // sets the enemy missile as active
+        }
+        // if enemy at 3rd row is dead, checks the enemy in the 2nd row
+        else if (enemyArray[firing_col+5]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile3.missile_blk_x = enemyArray[firing_col+5]->enemy_blk_x + (enemyArray[firing_col+5]->enemy_width/2);
+            enemy_missile3.missile_blk_y = enemyArray[firing_col+5]->enemy_blk_y + enemyArray[firing_col+5]->enemy_height + 1;
+            enemy_missile3.status = ENEMY_MISSILE_ACTIVE;
+        }
+        // if enemy at 2nd and 3rd row is dead, checks the enemy in the 1st row
+        else if (enemyArray[firing_col]->status == ENEMY_ALIVE)
+        {
+            // If alive, the enemy missile position is updated to the center of the enemy
+            enemy_missile3.missile_blk_x = enemyArray[firing_col]->enemy_blk_x + (enemyArray[firing_col]->enemy_width/2);
+            enemy_missile3.missile_blk_y = enemyArray[firing_col]->enemy_blk_y + enemyArray[firing_col]->enemy_height + 1;
+            enemy_missile3.status = ENEMY_MISSILE_ACTIVE;
+        }
+    } 
 }
 
 // moves the enemy
@@ -702,6 +777,7 @@
     while(1) {
         //while(numPlayers == 1) Thread::yield();
         rx = '0';
+        pc.printf("Slave thread running.\n\r");
         if (secondMbed.readable()) {
             rx = secondMbed.getc();
             pc.printf("rx = %c\n\r", rx);
@@ -709,8 +785,11 @@
             while (!secondMbed.writeable()) wait(0.5);
             secondMbed.putc(rx);
         }
+        Thread::wait(1000);
     }
 }
+*/
+
                 //first_player_ready = true;
                 //second_player_ready = true;
             //    begin_game2 = true;
@@ -744,11 +823,13 @@
 
 // UNCOMMENT THIS THREAD IF FIRST PLAYER AND COMMENT SLAVE THREAD
 // The master mbed device (second player) should uncomment this thread -- Brice
-/*
+
 void mbedMaster(void const *args) {
     char rx;
     while(1) {
+        pc.printf("Master called\n\r");
         while(numPlayers == 1) Thread::yield();
+        pc.printf("Num players is 2.\n\r");
         rx = '0';
         if (!begin_game2) {
             while(!secondMbed.writeable()) {
@@ -762,38 +843,40 @@
             }
             rx = secondMbed.getc();
             pc.printf("rx = %c\n\r", rx);
-            //if (rx == 'S') {
-            //    begin_game2 = true;
-            //    pc.printf("both players ready\n\r");
-            //}
+            if (rx == 'S') {
+                begin_game2 = true;
+                pc.printf("both players ready\n\r");
+            }
+        } else {
+            while (begin_game2) {
+                rx = '0';
+                if (secondMbed.readable()) {
+                    rx = secondMbed.getc();
+                    if (rx == 'W') {
+                        secondMbed.putc(rx);
+                        begin_game2 = false;
+                        two_player_lose = true;
+                    }
+                }
+                if (two_player_win) {
+                    secondMbed.putc('W');
+                    while(!secondMbed.readable()) wait(0.5); // ok to lock up with wait because we don't want to confirm when before anything else. --Brice
+                    rx = secondMbed.getc();
+                    if (rx == 'W') {
+                        begin_game2 = false;
+                    }
+                }
+                Thread::wait(1000);
+            }
         }
-        //} else {
-        //while (begin_game2) {
-        //    rx = '0';
-        //    if (secondMbed.readable()) {
-        //        rx = secondMbed.getc();
-        //        if (rx == 'W') {
-        //            secondMbed.putc(rx);
-        //            begin_game2 = false;
-        //            two_player_lose = true;
-        //        }
-        //    }
-        //    if (two_player_win) {
-        //        secondMbed.putc('W');
-        //        while(!secondMbed.readable()) wait(0.5); // ok to lock up with wait because we don't want to confirm when before anything else. --Brice
-        //        rx = secondMbed.getc();
-        //        if (rx == 'W') {
-        //            begin_game2 = false;
-        //        }
-        //    }
-        //    Thread::wait(1000);
-        //}
-        //Thread::wait(1000);
+        Thread::wait(1000);
     }
 }
-*/
+
+
 
 int main() {
+     //pc.printf("in main");
      IMU.begin();
      if (!IMU.begin()) {
          pc.printf("Failed to communicate with IMU\n\r");
@@ -807,7 +890,7 @@
      // Should only have the Slave thread uncommented if second player.
      // Should only have the Master thread uncommented if first player.
      //Thread thread2(mbedSlave); // uncommented if second player -- Brice
-     //Thread thread3(mbedMaster); // uncommented if first player -- Brice
+     Thread thread3(mbedMaster); // uncommented if first player -- Brice
      Thread thread4(ledEffects); // thread added for LED lighting effects -- Brice
      secondMbed.baud(9600);
      uLCD.baudrate(3000000); // set to 3000000 to increase smooth gameplay
@@ -820,7 +903,7 @@
     int level_cursor_x_pos = 5; // level cursor x-position
     int level_cursor_y_pos_start = 7; // level cursor y-position
     //int level_cursor_y_pos = 7; // initial level_cursor_y_pos @ start -- Added by Brice for more menu options
-    int level_cursor_y_pos_end = 11; // BOTTOM CURSOR POS -- Added by Brice for more menu options
+    int level_cursor_y_pos_end = 13; // BOTTOM CURSOR POS -- Added by Brice for more menu options
     int gameover_x_pos = 5; // gameover label x-position
     int gameover_y_pos = 5; // gameover label y-position
     int win_x_pos = 2; // congratulations label x-position
@@ -835,7 +918,24 @@
     int score = 0;
      
     // Additional globals added for two-player and one-player capabilities (by Brice)
-    
+    char buffer[3] = {0};
+    char c = {0};
+    char *token;
+    int i = 0;
+    int storedTime = 999;
+    SDLock.lock();
+    FILE *sdtime;
+    sdtime=fopen("/sd/besttime.txt","r");
+    if(sdtime==NULL) pc.printf("file open error!\n\n\r"); // added this for open error check
+    while ((c != '\n') && (i < 3)) {
+        c = fgetc(sdtime);
+        buffer[i] = c;
+        i++;
+    }
+    fclose(sdtime);
+    SDLock.unlock();
+    token = strtok(buffer, "\n");
+    storedTime = atoi(token); // convert string from file to integer
     // Begin game loop
     while(1)
     {
@@ -856,6 +956,26 @@
         //uLCD.locate(title_x_pos,title_y_pos); // "SPACE INVADERS" title position
         //uLCD.printf("SPACE INVADERS"); // Title
         // Implementation of Game Menu
+        
+        //char buffer[3] = {0};
+//        char c = {0};
+//        char *token;
+//        int i = 0;
+//        int storedTime = 999;
+//        SDLock.lock();
+//        FILE *sdtime;
+//        sdtime=fopen("/sd/besttime.txt","r");
+//        if(sdtime==NULL) pc.printf("file open error!\n\n\r"); // added this for open error check
+//        while ((c != '\n') && (i < 3)) {
+//            c = fgetc(sdtime);
+//            buffer[i] = c;
+//            i++;
+//        }
+//        fclose(sdtime);
+//        SDLock.unlock();
+//        token = strtok(buffer, "\n");
+//        storedTime = atoi(token); // convert string from file to integer
+        // Implementation of game_menu
         while(game_menu) 
         {
             float accelY = 0.0; // y acceleration
@@ -904,6 +1024,12 @@
             
             uLCD.locate(start_label_x_pos,start_label_y_pos + 4);
             uLCD.printf("LEVEL 3");
+            
+            uLCD.locate(start_label_x_pos, start_label_y_pos + 6);
+            uLCD.printf("TWO-PLAYER");
+            
+            uLCD.locate(2,15);
+            uLCD.printf("Best time: %d s", storedTime);
             // if pushbutton is pressed, game menu is exited and game begins
             if(!pb) 
             { 
@@ -917,6 +1043,9 @@
                     level = 2;
                 } else if (level_cursor_y_pos == start_label_y_pos + 4) {
                     level = 3;
+                } else if (level_cursor_y_pos == start_label_y_pos + 6) {
+                    numPlayers = 2;
+                    level = 1;
                 }
                 Thread::wait(500); // changed this to Thread::wait ... originally wait(0.5);
             }
@@ -924,6 +1053,7 @@
         while(numPlayers != 1 && !begin_game2) Thread::yield(); // added to force wait with two-player and one player not ready. -- added by Brice
         if (numPlayers == 2 && begin_game2) {
             numWins = 0;
+            bestTimer.start();
         } else {
             begin_game = true; // defaults begin_game to true
             
@@ -949,7 +1079,12 @@
         int e_blk_x = 0;
         int e_blk_y = 2;
         enemy_missile_init(&enemy_missile, e_blk_x, e_blk_y, WHITE);
-        
+        if (level == 2 || level == 3) {
+            enemy_missile_init(&enemy_missile2, e_blk_x, e_blk_y, WHITE);
+        }
+        if (level == 3) {
+            enemy_missile_init(&enemy_missile3, e_blk_x, e_blk_y, WHITE);
+        }
         // prints lives
         if (level == 1) {
             uLCD.locate(0,0);
@@ -989,10 +1124,16 @@
                     && missile.missile_blk_y+1-missile.missile_height <= barrier_1.barrier_blk_y+barrier_1.barrier_height
                     && missile.status == PLAYER_MISSILE_ACTIVE) 
             {
-                check_barrier(&barrier_1, &missile);
+                if (level == 1) {
+                    check_barrier(&barrier_1, &missile);
+                }
                 check_barrier(&barrier_2, &missile);
-                check_barrier(&barrier_3, &missile);
-                check_barrier(&barrier_4, &missile);
+                if (level == 1 || level == 2) {
+                    check_barrier(&barrier_3, &missile);
+                }
+                if (level == 1) {
+                    check_barrier(&barrier_4, &missile);
+                }
             }
             
             // checks if player missile passes y-pos of row1
@@ -1017,20 +1158,88 @@
             }
             
             // Random Enemy Fire
-            if (enemy_missile.status == ENEMY_MISSILE_INACTIVE) 
+            if (enemy_missile.status == ENEMY_MISSILE_INACTIVE || enemy_missile2.status == ENEMY_MISSILE_INACTIVE || enemy_missile3.status == ENEMY_MISSILE_INACTIVE) 
             {
                 random_attack_gen();
+                /*
+                if (level == 2 || level == 3) {
+                    random_attack_gen();
+                }
+                if (level == 3) {
+                    random_attack_gen();
+                }
+                */
             }
             
             // check if enemy missile passes the y-pos of the barrier and updates the barriers if they are hit.
             if (enemy_missile.missile_blk_y >= barrier_1.barrier_blk_y
                     && enemy_missile.missile_blk_y <= barrier_1.barrier_blk_y+barrier_1.barrier_height)
             {
-                check_barrier(&barrier_1, &enemy_missile);
+                if (level == 1) {
+                    check_barrier(&barrier_1, &enemy_missile);
+                }
                 check_barrier(&barrier_2, &enemy_missile);
-                check_barrier(&barrier_3, &enemy_missile);
-                check_barrier(&barrier_4, &enemy_missile);
+                if (level == 1 || level == 2) {
+                    check_barrier(&barrier_3, &enemy_missile);
+                }
+                if (level == 1) {
+                    check_barrier(&barrier_4, &enemy_missile);
+                }
+            }
+            
+            // check if enemy missile passes the y-pos of the barrier and updates the barriers if they are hit.
+            // Level 2 missile
+            if (level == 2 || level == 3) {
+                if (enemy_missile2.missile_blk_y >= barrier_1.barrier_blk_y
+                        && enemy_missile2.missile_blk_y <= barrier_1.barrier_blk_y+barrier_1.barrier_height)
+                {
+                    if (level == 1) {
+                        check_barrier(&barrier_1, &enemy_missile2);
+                    }
+                    check_barrier(&barrier_2, &enemy_missile2);
+                    if (level == 1 || level == 2) {
+                        check_barrier(&barrier_3, &enemy_missile2);
+                    }
+                    if (level == 1) {
+                        check_barrier(&barrier_4, &enemy_missile2);
+                    }
+                }
             }
+                        // Level 2 missile
+            if (level == 3) {
+                if (enemy_missile3.missile_blk_y >= barrier_1.barrier_blk_y
+                        && enemy_missile3.missile_blk_y <= barrier_1.barrier_blk_y+barrier_1.barrier_height)
+                {
+                    if (level == 1) {
+                        check_barrier(&barrier_1, &enemy_missile3);
+                    }
+                    check_barrier(&barrier_2, &enemy_missile3);
+                    if (level == 1 || level == 2) {
+                        check_barrier(&barrier_3, &enemy_missile3);
+                    }
+                    if (level == 1) {
+                        check_barrier(&barrier_4, &enemy_missile3);
+                    }
+                }
+            }
+            
+            /*
+            // check if enemy missile passes the y-pos of the barrier and updates the barriers if they are hit.
+            if (enemy_missile.missile_blk_y >= barrier_1.barrier_blk_y
+                    && enemy_missile.missile_blk_y <= barrier_1.barrier_blk_y+barrier_1.barrier_height)
+            {
+                if (level == 1) {
+                    check_barrier(&barrier_1, &enemy_missile);
+                }
+                check_barrier(&barrier_2, &enemy_missile);
+                if (level == 1 || level == 2) {
+                    check_barrier(&barrier_3, &enemy_missile);
+                }
+                if (level == 1) {
+                    check_barrier(&barrier_4, &enemy_missile);
+                }
+            }
+            */
             
             // checks if enemy missile passes y-pos of player
             if (enemy_missile.missile_blk_y >= player.player_blk_y
@@ -1039,10 +1248,32 @@
                 check_player_hit();
             }
             
-
+            // Level 2 check player hit
+            if (level == 2 || level == 3) {
+                if (enemy_missile2.missile_blk_y >= player.player_blk_y
+                    && enemy_missile2.missile_blk_y <= player.player_blk_y+player.player_height)
+                {
+                    check_player_hit();
+                }
+            }
+            
+            // Level 3 check player hit
+            if (level == 3) {
+                if (enemy_missile3.missile_blk_y >= player.player_blk_y
+                    && enemy_missile3.missile_blk_y <= player.player_blk_y+player.player_height)
+                {
+                    check_player_hit();
+                }
+            }
             update_missile_pos(&missile); // updates player missile position
             update_enemy_missile_pos(&enemy_missile); // updates enemy missile position
-
+            // level 2 missile
+            if (level == 2 || level == 3) {
+                update_enemy_missile_pos(&enemy_missile2);
+            }
+            if (level == 3) {
+                update_enemy_missile_pos(&enemy_missile3);
+            }
             // Player Movement checked with navigation switch
             //if (myNav.left() && ((player.player_blk_x-3) > 0))
             // With joystick click, change color of player from GREEN -> BLUE -> PINK -> PURPLE -> YELLOW (and loop).
@@ -1086,13 +1317,13 @@
             if ((accelX <= -0.25) && (player.player_blk_x + accelX*5) > 0.0) {
                 player_erase(&player);
                 //player.player_blk_x -= 3;
-                player.player_blk_x += (int)(accelX*5);
+                player.player_blk_x += (int)(accelX*8);
                 player_show(&player);
             //} else if (myNav.up() && level_cursor_y_pos > level_cursor_y_pos_start) {
             } else if ((accelX >= 0.25) && ((player.player_blk_x + accelX*5) < (128 - player.player_width))) {
                 player_erase(&player);
                 //player.player_blk_x -= 3;
-                player.player_blk_x += (int)(accelX*5);
+                player.player_blk_x += (int)(accelX*8);
                 player_show(&player);
             }
             // Player Fire
@@ -1147,7 +1378,7 @@
                 win = true; // sets win to true, for win screen
                 begin_game = false;
                 
-                // displays video clip ????
+                // displays video clip ????. Original intention here is a little obscure.
                 /*
                 uLCD.cls();
                 uLCD.media_init();
@@ -1277,7 +1508,6 @@
                 // game play loop
         while(begin_game2) 
         {
-            // updates score
             temp = score;
             score = (15-numOfEnemies)*15;
             
@@ -1290,7 +1520,17 @@
             
             // move enemy
             enemy_motion();
-
+            // check barriers for player missile hit
+            if (missile.missile_blk_y+1-missile.missile_height >= barrier_1.barrier_blk_y
+                    && missile.missile_blk_y+1-missile.missile_height <= barrier_1.barrier_blk_y+barrier_1.barrier_height
+                    && missile.status == PLAYER_MISSILE_ACTIVE) 
+            {
+                check_barrier(&barrier_1, &missile);
+                check_barrier(&barrier_2, &missile);
+                check_barrier(&barrier_3, &missile);
+                check_barrier(&barrier_4, &missile);
+            }
+            
             // checks if player missile passes y-pos of row1
             if (missile.missile_blk_y+1-missile.missile_height <= enemy_1.enemy_blk_y
                     && missile.missile_blk_y+1-missile.missile_height >= enemy_1.enemy_blk_y-enemy_1.enemy_height) 
@@ -1318,46 +1558,79 @@
                 random_attack_gen();
             }
             
+            // check if enemy missile passes the y-pos of the barrier and updates the barriers if they are hit.
+            if (enemy_missile.missile_blk_y >= barrier_1.barrier_blk_y
+                    && enemy_missile.missile_blk_y <= barrier_1.barrier_blk_y+barrier_1.barrier_height)
+            {
+                check_barrier(&barrier_1, &enemy_missile);
+                check_barrier(&barrier_2, &enemy_missile);
+                check_barrier(&barrier_3, &enemy_missile);
+                check_barrier(&barrier_4, &enemy_missile);
+            }
+            
             // checks if enemy missile passes y-pos of player
             if (enemy_missile.missile_blk_y >= player.player_blk_y
                     && enemy_missile.missile_blk_y <= player.player_blk_y+player.player_height)
             {
                 check_player_hit();
             }
+            
 
             update_missile_pos(&missile); // updates player missile position
             update_enemy_missile_pos(&enemy_missile); // updates enemy missile position
 
             // Player Movement checked with navigation switch
-            //if (myNav.left() && ((player.player_blk_x-3) > 0)) 
-            //{
-            //    player_erase(&player);
-            //    player.player_blk_x -= 3;
-            //    player_show(&player);
-            //} 
-            //else if (myNav.right() && ((player.player_blk_x+3) < (128-player.player_width))) 
-            //{
-            //    player_erase(&player);
-            //    player.player_blk_x += 3;
-            //    player_show(&player);
-            //}
             //if (myNav.left() && ((player.player_blk_x-3) > 0))
+            // With joystick click, change color of player from GREEN -> BLUE -> PINK -> PURPLE -> YELLOW (and loop).
+            prevAnalogClick = newAnalogClick;
+            newAnalogClick = stick.button();
+            if (newAnalogClick && !prevAnalogClick) { 
+                if (player.player_color == 0x00FF00) { // if GREEN (start)
+                    player.player_color = 0x0000FF; // BLUE
+                } else if (player.player_color == 0x0000FF) { // if BLUE
+                    player.player_color = 0xFFC0CB; // pink. hot pink: 0xFF69B4
+                } else if (player.player_color == 0xFFC0CB) { // if pink
+                    player.player_color = 0x800080; // Purple: 0x800080. periwinkle purple: 0xCCCCFF
+                } else if (player.player_color == 0x800080) { // if purple
+                    player.player_color = 0xFFFF00; // yellow. metallic gold: 0xD4AF37
+                } else if (player.player_color == 0xFFFF00) { // if yellow
+                    player.player_color = 0x00FF00; // set back to GREEN
+                }
+            }
+            // Control Player with Analog Joystick -- Brice    
             float stickDist = stick.xAxis();
-            if ((stickDist < 0.0) && (player.player_blk_x + stickDist > 0.0))
-            {
+            if ((stickDist < 0.0) && (player.player_blk_x + stickDist*3 > 0.0)){
                 player_erase(&player);
                 //player.player_blk_x -= 3;
-                player.player_blk_x += (int)(stickDist);
+                player.player_blk_x += (int)(stickDist*3);
                 player_show(&player);
             } 
             //else if (myNav.right() && ((player.player_blk_x+3) < (128-player.player_width)))
-            else if ((stickDist > 0.0) && ((player.player_blk_x + stickDist) < (128 - player.player_width))) 
+            else if ((stickDist > 0.0) && ((player.player_blk_x + stickDist*3) < (128 - player.player_width))) 
             {
                 player_erase(&player);
-                player.player_blk_x += (int)(stickDist);
+                player.player_blk_x += (int)(stickDist*3);
                 player_show(&player);
             }
-
+            // Control Player with IMU -- Brice
+            float accelX = 0.0; // x acceleration
+            if (IMU.accelAvailable()) {
+                IMU.readAccel();
+                accelX = IMU.calcAccel(IMU.ax);
+                //pc.printf("Calc Accel: %f", accelY);
+            }
+            if ((accelX <= -0.25) && (player.player_blk_x + accelX*5) > 0.0) {
+                player_erase(&player);
+                //player.player_blk_x -= 3;
+                player.player_blk_x += (int)(accelX*8);
+                player_show(&player);
+            //} else if (myNav.up() && level_cursor_y_pos > level_cursor_y_pos_start) {
+            } else if ((accelX >= 0.25) && ((player.player_blk_x + accelX*5) < (128 - player.player_width))) {
+                player_erase(&player);
+                //player.player_blk_x -= 3;
+                player.player_blk_x += (int)(accelX*8);
+                player_show(&player);
+            }
             // Player Fire
             if (pb == 0 && missile.status == PLAYER_MISSILE_INACTIVE) 
             {
@@ -1369,102 +1642,188 @@
             // checks if player destroyed all enemies
             if (numOfEnemies == 0)
             {
+                // idea for best-time reading and updating: https://os.mbed.com/questions/75718/i-want-to-assign-int-value-saved-in-sd-t/
+                int time = bestTimer.read();
+                bestTimer.stop();
+                bestTimer.reset();
                 uLCD.cls();
+                char buffer[3] = {0};
+                char c = {0};
+                char *token;
+                int i = 0;
+                int storedTime = 999;
+                SDLock.lock();
+                FILE *sdtime;
+                sdtime=fopen("/sd/besttime.txt","r");
+                if(sdtime==NULL) pc.printf("file open error!\n\n\r"); // added this for open error check
+                while ((c != '\n') && (i < 3)) {
+                    c = fgetc(sdtime);
+                    buffer[i] = c;
+                    i++;
+                }
+                token = strtok(buffer, "\n");
+                storedTime = atoi(token); // convert string from file to integer
+                fclose(sdtime);
+                if (time < storedTime) {
+                    uLCD.locate(2,10);
+                    uLCD.printf("NEW BEST TIME!");
+                    uLCD.locate(2,11);
+                    uLCD.printf("%d seconds!", time);
+                    sdtime = fopen("/sd/besttime.txt", "w");
+                    if (sdtime != NULL) {
+                        fprintf(sdtime, "%d\r\n", time);
+                        fclose(sdtime);
+                    } else {
+                        pc.printf("write: failed!\r\n");
+                    }
+                }
+                SDLock.unlock();
                 
-                win = true; // sets win to true, for win screen
-                numWins += 1;
-                if (numWins == 3) {
-                    //begin_game2 = false;  // Allow the mbed communication thread to change the begin_game2 bool to false after letting other mbed know.
-                    two_player_win = true;
-                }
+                two_player_win = true; // sets win to true, for win screen
+                win = true;
+                //begin_game = false;
                 
-                // displays video clip ???
+                // displays video clip ????
                 /*
                 uLCD.cls();
                 uLCD.media_init();
                 uLCD.set_sector_address(0x00, 0x00);
                 uLCD.display_video(0,0);
-                Thread::wait(1000); // changed from wait(1)
-                */ 
+                Thread::wait(1000); // changed from wait(1) to Thread::wait(1000) since we're using threads -- Brice
+                */
                 
-                uLCD.cls();
-                if (!two_player_win) {
-                    // prints "Number of Wins" on uLCD -- Brice. A step towards victory, not a complete victory.    
-                    uLCD.locate(win_x_pos,win_y_pos);
-                    uLCD.printf("YOU HAVE %d WINS!", numWins);
+                //uLCD.cls();
+                
+                // prints "Congratulations" on uLCD    
+                uLCD.locate(win_x_pos,win_y_pos);
+                uLCD.printf("CONGRATULATIONS!");
                 
-                    // prints "Continue?" and "Press pb..." Keep trying to get points --Brice.
-                    uLCD.locate(startover_x_pos, startover_y_pos);
-                    uLCD.printf("Continue?");
-                    uLCD.locate(startover_x_pos, startover_y_pos+1);
-                    uLCD.printf("Press pb...");
+                // prints "Play Again?" and "Press pb..."
+                uLCD.locate(startover_x_pos, startover_y_pos);
+                uLCD.printf("Play again?");
+                uLCD.locate(startover_x_pos, startover_y_pos+1);
+                uLCD.printf("Press pb...");
                 
-                    // waits at win screen until pushbutton is pressed
-                    while (win)
+                // waits at win screen until pushbutton is pressed
+                while (two_player_win)
+                {
+                    // if pb is pressed, reset game to start menu
+                    if (!pb)
                     {
-                        // if pb is pressed, reset game to start menu
-                        if (!pb)
-                        {
-                            win = false;
-                            Thread::wait(500); // changed from wait(0.5) since we have threads -- Brice
-                        }
+                        win = false;
+                        two_player_win = false;
+                        begin_game2 = false;
+                        numPlayers = 1;
+                        game_menu = true;
+                        Thread::wait(500); // changed from wait(0.5) to Thread::wait(500) since we're using threads
                     }
-                } else {
-                    // prints CONGRATULATIONS! since player has won. --Brice 
-                    uLCD.locate(win_x_pos,win_y_pos);
-                    uLCD.printf("CONGRATULATIONS!"); 
-                
-                    // prints "Return to menu?" and "Press pb..." --Brice.
-                    uLCD.locate(startover_x_pos, startover_y_pos);
-                    uLCD.printf("Return to menu?");
-                    uLCD.locate(startover_x_pos, startover_y_pos+1);
-                    uLCD.printf("Press pb...");
+                }/*
+                REMOVED THIS AND MADE THE WINNER THE FIRST TO 1 WIN
+                if (numWins == 3) {
+                    two_player_win = true;
+                    while(two_player_win) {
+                        // if pb is pressed, reset game to start menu
+                        Thread::wait(2000);
+                        uLCD.locate(win_x_pos,win_y_pos);
+                        uLCD.printf("CONGRATULATIONS!");
                 
-                    // waits at win screen until pushbutton is pressed
-                    while (two_player_win)
-                    {
-                        // if pb is pressed, reset game to start menu
-                        if (!pb)
-                        {
-                            two_player_win = false; // close win -- Brice
-                            game_menu = true; // go back to menu -- Brice
-                            Thread::wait(500); // changed from wait(0.5) since we have threads -- Brice
-                        }
-                    }
+                        // prints "Play Again?" and "Press pb..."
+                        uLCD.locate(startover_x_pos, startover_y_pos);
+                        uLCD.printf("Play Again?");
+                        uLCD.locate(startover_x_pos, startover_y_pos+1);
+                        uLCD.printf("Press pb...");
+                            if (!pb)
+                            {
+                                two_player_win = false;
+                                begin_game2 = false;
+                                game_menu = true;
+                                Thread::wait(500); // changed from wait(0.5) to Thread::wait(500) since we're using threads
+                            }
+                    }   
                 }
+                */
+                
             }
-            
+            int prevColor;
             // checks if player was hit
             if (hit_player)
             {
                 // updates lives
-                lives1 -= 1;
-                Thread::wait(500); // changed from wait(0.5) since we're using threads --Brice
-                hit_player = 0;
-                player_show(&player);
-                player.status = PLAYER_ALIVE;
+                if (level == 1) {
+                    lives1 -= 1;
+                    prevColor = player.player_color;
+                    player_erase(&player);
+                    player.player_color = 0xFF0000; // briefly flash the player red.
+                    player_show(&player);
+                    Thread::wait(500); // changed from wait(0.5) to Thread::wait since we're using threads -- Brice
+                    player_erase(&player);
+                    player.player_color = prevColor; // briefly flash the player red.
+                    player_show(&player);
+                    hit_player = 0; 
+                    player_show(&player);
+                    player.status = PLAYER_ALIVE;
                 
                 // prints updated lives number
-                uLCD.locate(0,0);
-                uLCD.printf("Lives:%i", lives1);
+                    uLCD.locate(0,0);
+                    uLCD.printf("Lives:%i", lives1);
+                } else if (level == 2) {
+                    lives2 -= 1;
+                    prevColor = player.player_color;
+                    player_erase(&player);
+                    player.player_color = 0xFF0000; // briefly flash the player red.
+                    player_show(&player);
+                    Thread::wait(500); // changed from wait(0.5) to Thread::wait since we're using threads -- Brice
+                    player_erase(&player);
+                    player.player_color = prevColor; // briefly flash the player red.
+                    player_show(&player);
+                    //Thread::wait(500); // changed from wait(0.5) to Thread::wait since we're using threads -- Brice
+                    hit_player = 0;
+                    player_show(&player);
+                    player.status = PLAYER_ALIVE;
+                
+                // prints updated lives number
+                    uLCD.locate(0,0);
+                    uLCD.printf("Lives:%i", lives2);
+                } else if (level == 3) {
+                    lives3 -= 1;
+                    prevColor = player.player_color;
+                    player_erase(&player);
+                    player.player_color = 0xFF0000; // briefly flash the player red.
+                    player_show(&player);
+                    Thread::wait(500); // changed from wait(0.5) to Thread::wait since we're using threads -- Brice
+                    player_erase(&player);
+                    player.player_color = prevColor; // briefly flash the player red.
+                    player_show(&player);
+                    //Thread::wait(500); // changed from wait(0.5) to Thread::wait since we're using threads -- Brice
+                    hit_player = 0;
+                    player_show(&player);
+                    player.status = PLAYER_ALIVE;
+                
+                // prints updated lives number
+                    uLCD.locate(0,0);
+                    uLCD.printf("Lives:%i", lives3);
+                }
             }   
             
             // if player loses all lives or enemy reaches the player
-            if (lose || lives1 == 0)
+            if (lose || lives1 == 0 || lives2 == 0 || lives3 == 0)
             {    
-                //begin_game = false; // set to false to end game -- not needed in two-player, just keep playing until a player reaches 3 wins -- Brice
+                //begin_game = false; // set to false to end game
+                lives1 = 3;
                 uLCD.cls();
                 
+                two_player_lose = true;
                 gameover = true; // set to go to display gameover screen
+                numPlayers = 1;
                 
                 // prints "GAMEOVER" to uLCD
                 uLCD.locate(gameover_x_pos, gameover_y_pos);
-                uLCD.printf("YOU DIED");
-                Thread::wait(1000); // changed from wait(1) since we have multiple threads -- Brice
+                uLCD.printf("GAMEOVER");
+                Thread::wait(1000); // changed from wait(1) to thread::wait since we're using threads -- Brice
                 
                 // prints "Play Again?" and "Press pb..."
                 uLCD.locate(startover_x_pos, startover_y_pos);
-                uLCD.printf("Keep trying!");
+                uLCD.printf("Play again?");
                 uLCD.locate(startover_x_pos, startover_y_pos+1);
                 uLCD.printf("Press pb...");
                 
@@ -1475,43 +1834,41 @@
                     if (!pb)
                     {
                         gameover = false;
-                        //game_menu = true; // removed since other player must win three times for game to be over.
-                        Thread::wait(500); // changed from wait(0.5) since we have threads.
+                        two_player_lose = false;
+                        game_menu = true;
+                        begin_game2 = false;
+                        numPlayers = 1;
+                        //game_menu = true;
+                        Thread::wait(500); // changed wait(0.5) to Thread::wait since we're using threads -- Brice
                     }
                 }
             }
-            if (two_player_lose)
-            {    
-                begin_game2 = false; // set to false to end game. End game since other player won.
+            if (two_player_lose) {
                 uLCD.cls();
-                
-                gameover = true; // set to go to display gameover screen
+                numPlayers = 1;
+                Thread::wait(2000);
+                uLCD.locate(gameover_x_pos, gameover_y_pos);
+                uLCD.printf("You lost!");
+                Thread::wait(1000); // changed from wait(1) to thread::wait since we're using threads -- Brice
                 
-                // prints "GAMEOVER" to uLCD
-                uLCD.locate(gameover_x_pos, gameover_y_pos);
-                uLCD.printf("GAMEOVER");
-                Thread::wait(1000); // thread wait since we have multiple threads -- Brice
-                
-                // prints "Return to menu?" and "Press pb..."
+                // prints "Play Again?" and "Press pb..."
                 uLCD.locate(startover_x_pos, startover_y_pos);
-                uLCD.printf("Return to menu?"); 
+                uLCD.printf("Continue?");
                 uLCD.locate(startover_x_pos, startover_y_pos+1);
                 uLCD.printf("Press pb...");
+            }
+            while(two_player_lose) {
+                //uLCD.cls();
                 
-                // stays in gameover screen until pb is pressed
-                while (gameover)
-                {
-                    // if pb is pressed, game is reset to the game menu screen
-                    if (!pb)
+                if (!pb)
                     {
-                        gameover = false;
-                        two_player_lose = false; // end lose.
-                        game_menu = true; // removed since other player must win three times for game to be over.
-                        Thread::wait(500); // changed from wait(0.5) since we have threads.
+                        two_player_lose = false;
+                        game_menu = true;
+                        begin_game2 = false;
+                        numPlayers = 1;
+                        Thread::wait(500); // changed wait(0.5) to Thread::wait since we're using threads -- Brice
                     }
                 }
             }
-
         }
     }
-}
\ No newline at end of file