Missile Command Game

Dependencies:   mbed wave_player 4DGL-uLCD-SE MMA8452

Files at this revision

API Documentation at this revision

Comitter:
bpritchettjr
Date:
Sat Jul 23 03:28:14 2022 +0000
Parent:
1:5724f2947554
Commit message:
Final game

Changed in this revision

doubly_linked_list.cpp Show annotated file Show diff for this revision Revisions of this file
hardware.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
player.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 5724f2947554 -r a09accf52491 doubly_linked_list.cpp
--- a/doubly_linked_list.cpp	Tue May 11 18:26:14 2021 +0000
+++ b/doubly_linked_list.cpp	Sat Jul 23 03:28:14 2022 +0000
@@ -14,11 +14,19 @@
 
 LLNode* create_llnode(void* data) {
     // complete this function (see doubly_linked_list.h for documentation)
-    LLNode* newNode;
+    
+    // original head
+    LLNode* newNode = (LLNode*)malloc(sizeof(LLNode));
+    newNode->data = data;
+    newNode->prev = NULL;
+    newNode->next = NULL;
+    
+    
     return newNode;
 }
 
 DLinkedList* create_dlinkedlist(void) {
+    //empty list
     DLinkedList* newList = (DLinkedList*)malloc(sizeof(DLinkedList));
     newList->head = NULL;
     newList->tail = NULL;
@@ -26,13 +34,78 @@
     return newList;
 }
 
-void insertHead(DLinkedList* dLinkedList, void* data){
-  LLNode* newNode = create_llnode(data);
-  // complete this function
+void insertHead(DLinkedList* dLinkedList, void* data){  // insert head only called once so there is only one node 
+    LLNode* newNode = create_llnode(data);
+    // complete this function
+    
+   /* newNode->next = dLinkedList->head;   // the new node next points to the original head of the list 
+    dLinkedList->head = newNode;  // head of DLL points points to new node
+    newNode->prev = NULL;         // new node prev points to NULL since it the node is inserted as a head
+    
+    
+            
+    newNode->next->prev = newNode;       // the prev of the orignal node now points to the new node
+    
+    dLinkedList->size += 1;  //maybe */
+    if(dLinkedList->head ==NULL) {
+        dLinkedList->head = newNode;
+        dLinkedList->tail = newNode;
+        dLinkedList->size = 1;
+        return;
+    }
+
+    //insert a node when the list is not empty
+    newNode->next = dLinkedList->head;
+    dLinkedList->head->prev = newNode;
+    dLinkedList->head = newNode;
+    dLinkedList->size++;
+
+  
 }
 
 void deleteNode(DLinkedList* dLinkedList, LLNode* Node){
   // complete this function
+  
+    LLNode *temp = dLinkedList->head;
+    
+    if(dLinkedList->head == Node) {         //check if head is equal to Node
+        LLNode *temp = dLinkedList->head;
+
+        dLinkedList->head = dLinkedList->head->next;     //advance head by one node
+        
+        if(dLinkedList->head == NULL){
+            dLinkedList->tail = NULL;
+        }
+        else{
+            dLinkedList->head->prev = NULL;
+        }
+
+        dLinkedList->size--;       //decrease the size by one
+
+        free(temp);   //dealloacation of memory
+        return;
+    }
+    
+    while(temp!=NULL && temp!=Node){  //traverse the list
+
+        temp = temp->next;
+    }
+
+    if(temp == NULL) return;     //if node is not found
+
+    LLNode *a = temp->prev;    //delete node
+    LLNode *b = temp->next;
+
+    a->next = b;
+    if(b != NULL) {
+        b->prev = a;
+    }
+
+    dLinkedList->size--;    //decrease the size by one
+
+    free(temp);  //dealloacation of memory
+    
+  
 }
 
 void destroyList(DLinkedList* dLinkedList){
diff -r 5724f2947554 -r a09accf52491 hardware.cpp
--- a/hardware.cpp	Tue May 11 18:26:14 2021 +0000
+++ b/hardware.cpp	Sat Jul 23 03:28:14 2022 +0000
@@ -30,6 +30,7 @@
     button2.mode(PullUp);
     button3.mode(PullUp);
     
+    
     return ERROR_NONE;
 }
 
@@ -41,7 +42,13 @@
     in.b3 = !button3;
     // Read Accelerometer and record ax, ay, az in the GameInputs structure.
     // Complete this function (hint: lookup mbed Hardware > Components > find the accelerometer you are using)
- 
+    
+    acc.readXGravity(&in.ax);    //Read the x accelerations measured in G
+    acc.readYGravity(&in.ay);   //Read the y accelerations measured in G
+    acc.readZGravity(&in.az);   //Read the z accelerations measured in G
+   
+    
+    
     // pc.printf("Inputs: %d %d %d %f %f %f\r\n", inputs.b1, inputs.b2, inputs.b3, inputs.ax, inputs.ay, inputs.az);
     return in;
 }
diff -r 5724f2947554 -r a09accf52491 main.cpp
--- a/main.cpp	Tue May 11 18:26:14 2021 +0000
+++ b/main.cpp	Sat Jul 23 03:28:14 2022 +0000
@@ -1,10 +1,10 @@
 //=================================================================
 // The main program file.
 //
-// Copyright 2021 Georgia Tech.  All rights reserved.
+// CoplayerYright 2021 Georgia Tech.  All rights reserved.
 // The materials provided by the instructor in this course are for
 // the use of the students currently enrolled in the course.
-// Copyrighted course materials may not be further disseminated.
+// CoplayerYrighted course materials may not be further disseminated.
 // This file must not be made publicly available anywhere.
 //==================================================================
 
@@ -18,15 +18,26 @@
 #include "missile_public.h"
 #include "player_public.h"
 
+
 #define CITY_HIT_MARGIN 1
 #define CITY_UPPER_BOUND (SIZE_Y-(LANDSCAPE_HEIGHT+MAX_BUILDING_HEIGHT))
 
 int num_city_g = 4;
+int currScore = 0;  // current score
+int topScore = 0;  // top score
+int level = 1;  // game level
 // function prototypes
 void set_random_seed(Timer);
 int city_landscape_update(void);
 int was_player_hit(void);
 void missile_contact(void); 
+void endGame(void);
+void display_topScore(void);
+//void explosion(int leftSide, int rightSide, int subHeight);
+
+
+
+
 
 int main()
 {
@@ -36,8 +47,11 @@
     pc.printf("Program Starting");
 
     // Game state variables
-    int num_remain_city; // number of cities currently on the landscape
-    int player_alive; // 1 if alive, 0 if hit
+    int num_remain_city = 4; // number of cities currently on the landscape
+    int player_alive = 3; // 1 if alive, 0 if hit
+    int check_hit = 1;
+    //int topScore = 0;
+    
     
     testDLL();
     // Timer to measure game update speed (secondarily used to generate random seed)
@@ -51,13 +65,55 @@
     player_init();        
     pc.printf("Initialization complete\n");
 
+     
+   
+    
     while(1)
     {
+        
         t.start();
+        
+        
+        
+        uLCD.locate(1,0);
+        //uLCD.set_font_size(1, 1);
+        uLCD.printf("Score:%d", currScore);
+        
+        uLCD.locate(11,0);
+        //uLCD.set_font_size(2, 2);
+        uLCD.printf("Lives:%d", player_alive);
+        
+        
+        
+        inputs = read_inputs();
+        
         // Generate new missiles and draw all active missiles at current 
         // positions. (Already implemented.)
         missile_generator();
         
+        
+        
+        // You must write the code to dispatch to the correct action (e.g., 
+        // player_moveLeft/Right, player_fire, etc.) based on the inputs read.
+        // You must also implement player_moveLeft/moveRight/fire (see player
+        // module).
+        GameInputs in = read_inputs();
+        
+        if(in.ax > 0.05) {
+               player_moveRight();
+        }
+        
+        if(in.ax < -0.05) {
+               player_moveLeft(); 
+        }
+        
+        if(inputs.b2){
+                player_fire();
+        }
+             
+        
+        
+        
         // Draw all active anti-missiles (aka player missiles) at current 
         // positions. (Already implemented.)
         player_missile_draw();
@@ -68,24 +124,33 @@
         
         // Detect missile collision with player aircraft.
         // You need to implement this (see specification below).
-        player_alive = was_player_hit(); //returns 0 if player is hit; else 1
+       // player_alive = was_player_hit(); //returns 0 if player is hit; else 1
         
         // Detect missile collisions with player anti-missiles.
         // You need to implement this (see specification below).
         missile_contact();
+        
+        check_hit = was_player_hit();
+        
+        
+        if(check_hit == 1) {
+            if(player_alive == 0) {      // if player out of lives after being hit, game over
+                player_destroy();
+                break;
+            }
+           player_alive = player_alive - 1;  // lives decremented by 1 
+        }
+        
+        if(num_remain_city == 0 || player_alive == 0) { // if all cities are destroyed or player is out of lives, game over
+            break;
+        }
     
         // You must complete the implementation of this function in hardware.cpp:
-        inputs = read_inputs();
+        //inputs = read_inputs();
 
-        // You must write the code to dispatch to the correct action (e.g., 
-        // player_moveLeft/Right, player_fire, etc.) based on the inputs read.
-        // You must also implement player_moveLeft/moveRight/fire (see player
-        // module).
-
-               
-        // You must write code to detect and implement game over.        
-        if (player_alive) break; // replace this line
-
+                 
+    
+        
         // Compute update time to control timing of the game loop.
         // (Already implemented... you're welcome.)
         t.stop();
@@ -94,13 +159,61 @@
     }
     pc.printf("out of main loop\n");
     
+    
+    
+     
+    
+    
     // You must write code to free up any dynamically allocated objects such
     // as lists of missiles (hint: destroyList can be used for doubly linked
     // lists).
+    DLinkedList* missileList = get_missile_list();
+    destroyList(missileList);
+    PLAYER pmissile = player_get_info();
+    DLinkedList* pmiss = pmissile.playerMissiles;
+    destroyList(pmiss);
     
-    return 0;
+    endGame();
 }
 
+
+void explosion(int status, int a, int b, int waitTime) {
+        if(status == 0) { // explosion animation for missile
+            uLCD.circle(a, b, 10, 0xFCC603);
+            wait(waitTime);
+            uLCD.circle(a, b, 10, BACKGROUND_COLOR); // yellow explosion
+            wait(waitTime);
+            uLCD.circle(a, b, 8, 0xFCC603); 
+            wait(waitTime);
+            uLCD.circle(a, b, 8, BACKGROUND_COLOR); // yellow explosion
+            wait(waitTime);
+            uLCD.circle(a, b, 6, 0xFCC603);
+            wait(waitTime);
+            uLCD.circle(a, b, 6, BACKGROUND_COLOR);  // yellow explosion
+            
+        }
+        
+        if(status == 1) {  // destruction animation for city and player
+            uLCD.circle(a, b, 10, 0xFF00FF); // blue explosion
+            wait(waitTime);
+            uLCD.circle(a, b, 10, BACKGROUND_COLOR);
+            wait(waitTime);
+            uLCD.circle(a, b, 8, 0xFF00FF); // blue explosion
+            wait(waitTime);
+            uLCD.circle(a, b, 8, BACKGROUND_COLOR);
+            wait(waitTime);
+            uLCD.circle(a, b, 6, 0xFF00FF); // blue explosion
+            wait(waitTime);
+            uLCD.circle(a, b, 6, BACKGROUND_COLOR);
+        }
+    }
+
+
+
+
+
+
+
 /** Detect whether any missile has hit a city and if so, call 
     city_demolish (hint: city_get_info may be useful).
     Also, if any missile has hit a city or the landscape,
@@ -111,6 +224,42 @@
 */
 int city_landscape_update(void){
     // Complete this function.
+    
+    int j;
+    const int i = num_city_g;
+    int c1, c2, c3, c4;
+    int leftSide, rightSide, subHeight;
+    DLinkedList* miss = get_missile_list();
+    LLNode* currMissile = miss->head;
+    
+    while(currMissile) {
+        MISSILE* attack = (MISSILE*) currMissile->data;
+        for(j = 0; j <= i; j++) {
+            CITY activeCity = city_get_info(j);
+            switch(activeCity.status) {
+                case DEMOLISHED:
+                    break;
+                case EXIST:
+                    leftSide = activeCity.x;
+                    rightSide = activeCity.width + leftSide;
+                    subHeight = 128 - activeCity.height;
+                    c1 = attack->x - rightSide;
+                    c2 = leftSide - attack->x;
+                    c3 = 128 - attack->y;
+                    c4 = subHeight - attack->y;
+                    
+                    if( (c1<=0) && (c2<=0) && (c3>=1) && (c4<=0) ) { //city collision starts
+                        activeCity.status = DEMOLISHED;
+                        city_demolish(j);
+                        attack->status = MISSILE_EXPLODED;
+                        num_city_g = num_city_g - 1; // remaining cities
+                        explosion(1,0.5*(leftSide + rightSide),subHeight,0.1);
+                    }
+            }   
+        }
+        currMissile = currMissile->next;
+    }
+    
     return num_city_g;
 }
 
@@ -121,7 +270,25 @@
     @return 1 if the player aircraft was hit and 0 otherwise.
 */
 int was_player_hit(){
+    
+    int enemyX, enemyY;
+    
+    PLAYER activePlayer = player_get_info();
+    DLinkedList* miss = get_missile_list();
+    LLNode* enemyMiss = miss->head;
+    while(enemyMiss) {
+        MISSILE* enemy = (MISSILE*) enemyMiss->data;
+        enemyX = enemy->x;
+        enemyY = enemy->y;
+        if( ((enemyY - activePlayer.y < 1) && (activePlayer.y - enemyY) < 5) && ((activePlayer.x - enemyX) < 1 && (enemyX - activePlayer.x) < 5 )) {
+            enemy->status = MISSILE_EXPLODED;   
+            return 1;    // when player is hit, return back to while loop
+        }
+        enemyMiss = enemyMiss->next;
+    }
     return 0;
+    
+    
 }
 
 /** Detect whether any missile has hit any player missile and if so, 
@@ -130,6 +297,39 @@
     from the screen on the next missile_generator call.
 */
 void missile_contact(void) {
+    int enemyX, enemyY, playerX, playerY;
+    
+    PLAYER activePlayer = player_get_info();
+    DLinkedList* pmiss = activePlayer.playerMissiles;
+    
+    DLinkedList* miss = get_missile_list();
+    LLNode* pMiss = pmiss->head;
+    LLNode* enemyMiss = miss->head;
+    MISSILE* enemy;
+    PLAYER_MISSILE* defend;
+    while(pMiss) {
+        defend = (PLAYER_MISSILE*) pMiss->data;
+        playerX = defend->x;
+        playerY = defend->y;
+        while(enemyMiss) {
+            enemy = (MISSILE*) enemyMiss->data;
+            enemyX = enemy->x;
+            enemyY = enemy->y;
+            if((enemyX - playerX)*(enemyX - playerX)+(enemyY - playerY)*(enemyY - playerY) < 100) { // distance < radius
+                defend->status = PMISSILE_EXPLODED;
+                enemy->status = MISSILE_EXPLODED;
+                explosion(0,0.5*(enemyX + playerX),0.5*(enemyY + playerY),0.1);
+                currScore = currScore + 1;        // player score increeased by 1
+            }
+            enemyMiss = enemyMiss->next;
+        }
+        if(enemyY > 128) {
+            enemy->status = MISSILE_EXPLODED;
+        }  
+        pMiss = pMiss->next;  
+    }
+    
+    
 }
 
 /* We need a random number generator (e.g., in missile_create to generate
@@ -157,3 +357,29 @@
     srand(seed);
     }
 
+       // You must write code to detect and implement game over.        
+    void endGame() {
+        uLCD.cls();
+        uLCD.locate(5,3);
+        uLCD.printf("Game Over");
+        uLCD.locate(5,4);
+        uLCD.printf("Score: %d", currScore);
+        if(topScore <= currScore && currScore != 0) {
+            topScore = currScore;
+            uLCD.locate(5,6);
+            uLCD.printf("High Score!");
+            uLCD.locate(5,9);
+            uLCD.printf("Good job"); 
+        }
+        wait(10);
+        uLCD.cls();
+    }  
+    
+     // display highest score
+    void display_topScore() {
+        uLCD.locate(4,7);
+        uLCD.printf("Highest score: %d", topScore);
+        wait(10);
+        uLCD.cls();    
+    }
+
diff -r 5724f2947554 -r a09accf52491 player.cpp
--- a/player.cpp	Tue May 11 18:26:14 2021 +0000
+++ b/player.cpp	Sat Jul 23 03:28:14 2022 +0000
@@ -30,17 +30,43 @@
     // Complete this function.  Hint: one way to animate moving an object is to
     // "erase" it at its current position (draw it using the background color)
     // and redraw it at the new position.
+    
+    /*if( player.x - player.delta < 0) {
+        return;
+    }
+    player_draw(BACKGROUND_COLOR);
+    player.x = player.x - player.delta;
+    player_draw(PLAYER_COLOR); */
+    
+    if(player.x > 0) {
+        player_draw(BACKGROUND_COLOR);
+        player.x = player.x - player.delta;
+        player_draw(PLAYER_COLOR);
+    }
 }
 
 // move player PLAYER_DELTA pixels to the right, except if it would go off screen.
 void player_moveRight(void) { 
     // Complete this function.
+    if(player.x < 128-player.width) {
+    
+        player_draw(BACKGROUND_COLOR);
+        player.x = player.x + player.delta;
+        player_draw(PLAYER_COLOR);
+    }
 }
 
 // generate an active missile to shoot 
 void player_fire() { 
     // Complete this function.  It should allocate a PLAYER_MISSILE, initialize
     // it and insert it into the player's playerMissiles list.
+    PLAYER_MISSILE* pm = (PLAYER_MISSILE*) malloc(sizeof(PLAYER_MISSILE)); // allocate
+    pm->status = PMISSILE_ACTIVE;
+    pm->x = player.x + player.width/2;   // missile location
+    pm->y = player.y - player.delta;
+    insertHead(player.playerMissiles, pm); // add missile to list
+    
+
 }
 
 // draw/updates the line of any active missiles, "erase" deactive missiles
@@ -81,6 +107,7 @@
 void player_draw(int color) {
     uLCD.filled_rectangle(player.x, player.y, player.x+player.width, player.y+player.height, color); 
     uLCD.filled_rectangle(player.x+player.delta, player.y-player.delta, player.x+player.width-player.delta, player.y+player.height, color);
+    
 }
 
 // destroy and "erase" the player off the screen. change status to DESTROYED