![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Missile Command Game
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
Revision 2:a09accf52491, committed 2022-07-23
- Comitter:
- bpritchettjr
- Date:
- Sat Jul 23 03:28:14 2022 +0000
- Parent:
- 1:5724f2947554
- Commit message:
- Final game
Changed in this revision
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