ECE2035 class project
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed wave_player
Fork of missile_command by
Revision 2:d39a6a36e0c0, committed 2014-11-17
- Comitter:
- slin77
- Date:
- Mon Nov 17 13:15:34 2014 +0000
- Parent:
- 1:3da29f1d84b4
- Child:
- 3:fd1f794b7f5d
- Commit message:
- first commit
Changed in this revision
--- a/city_landscape/city_landscape.cpp Wed Oct 29 02:58:53 2014 +0000 +++ b/city_landscape/city_landscape.cpp Mon Nov 17 13:15:34 2014 +0000 @@ -21,9 +21,11 @@ */ #include "city_landscape_private.h" +#include "globals.h" +// +//CITY city_record[]; +int building_height[NUM_BUILDING]; -CITY city_record[MAX_NUM_CITY]; -int building_height[NUM_BUILDING]; // See the comments in city_landscape_public.h void city_landscape_init(int num_city) { @@ -112,6 +114,17 @@ } } +int is_any_left() { + int i, left = 0; + for (i = 0; i < MAX_NUM_CITY; i++) { + if (city_record[i].status == EXIST) { + left = 1; + break; + } + } + return left; +} + void draw_landscape(void){ uLCD.filled_rectangle(0, SIZE_Y-1, SIZE_X-1, REVERSE_Y(LANDSCAPE_HEIGHT), LANDSCAPE_COLOR); } \ No newline at end of file
--- a/city_landscape/city_landscape_private.h Wed Oct 29 02:58:53 2014 +0000 +++ b/city_landscape/city_landscape_private.h Mon Nov 17 13:15:34 2014 +0000 @@ -51,7 +51,7 @@ #define BUILDING_WIDTH 2 // pixel on the screen #define NUM_BUILDING (CITY_WIDTH/BUILDING_WIDTH) #define BUILDING_COLOR 0x00FF00 -#define LANDSCAPE_COLOR 0xCCAA00 +//#define LANDSCAPE_COLOR 0xCCAA00
--- a/city_landscape/city_landscape_public.h Wed Oct 29 02:58:53 2014 +0000 +++ b/city_landscape/city_landscape_public.h Mon Nov 17 13:15:34 2014 +0000 @@ -22,6 +22,7 @@ /** @file city_landscape_public.h */ #ifndef CITY_LANDSCAPE_PUBLIC_H #define CITY_LANDSCAPE_PUBLIC_H +#define LANDSCAPE_COLOR 0xCCAA00 /// The enum define the status of a city typedef enum { @@ -67,5 +68,7 @@ */ void draw_landscape(void); +int is_any_left(); + #endif //CITY_LANDSCAPE_H \ No newline at end of file
--- a/globals.h Wed Oct 29 02:58:53 2014 +0000 +++ b/globals.h Mon Nov 17 13:15:34 2014 +0000 @@ -21,9 +21,16 @@ */ #ifndef GLOBAL_H #define GLOBAL_H - +#include "missile_public.h" +#include "player.h" +#include "city_landscape_public.h" // === [global object] === extern uLCD_4DGL uLCD; +extern PLAYER current_player; +extern ANTIMISSILE am[5]; +extern EXPLOSION ex[5]; +extern MISSILE missile_record[MAX_NUM_MISSILE]; +extern CITY city_record[MAX_NUM_CITY]; // === [global settings] ===
--- a/main.cpp Wed Oct 29 02:58:53 2014 +0000 +++ b/main.cpp Mon Nov 17 13:15:34 2014 +0000 @@ -32,9 +32,12 @@ #include "city_landscape_public.h" #include "missile_public.h" #include "player.h" +#include <stdio.h> +#include <stdlib.h> // Platform initialization DigitalIn left_pb(p23); DigitalIn right_pb(p21); DigitalIn fire_pb(p22); +DigitalIn fouth_pb(p24); uLCD_4DGL uLCD(p28,p27,p29); AnalogOut DACout(p18); wave_player waver(&DACout); @@ -42,64 +45,156 @@ // Example of the decleration of your implementation void playSound(char * wav); +void check_interception(); +int within_range(MISSILE m, ANTIMISSILE a); +int check_destruction_range(MISSILE m,CITY c); +void check_city_destruction(); +void display_victory(); +void display_failure(); +void advance_level(); + + +PLAYER current_player; +CITY city_record[]; +MISSILE missile_record[]; +ANTIMISSILE am[]; +EXPLOSION ex[]; + +int number_of_cities = 4; /** Main() is where you start your implementation @brief The hints of implementation are in the comments. <br> @brief You are expected to implement your code in main.cpp and player.cpp. But you could modify any code if you want to make the game work better. */ + + int main() { - // [Demo of 7-segment display] - // 1.Initialize the segment display + setup_sequence(); - seg_driver_initialize(); - // 2.show numbers - int i; - for(i=0;i<10;i++){ - seg_driver(i); - wait(0.2); - } - - // [Demo of play sound file] - playSound("/sd/wavfiles/BUZZER.wav"); - - /// [Example of missile command implementation] - /// Here is a rough flow to implement the missile command: <br><br> - - /// 1.Initialize and draw the city landscape - city_landscape_init(4); + seg_driver_initialize(); + city_landscape_init(number_of_cities); // Initialize the buttons left_pb.mode(PullUp); // The variable left_pb will be zero when the pushbutton for moving the player left is pressed right_pb.mode(PullUp); // The variable rightt_pb will be zero when the pushbutton for moving the player right is pressed - fire_pb.mode(PullUp); //the variable fire_pb will be zero when the pushbutton for firing a missile is pressed + fire_pb.mode(PullUp); + fouth_pb.mode(PullUp); //the variable fouth_pb will be zero when the pushbutton for firing a missile is pressed + player_init();//initalize the player + antimissile_init(); + explosion_init(); + //display the game menu + int k; + while (1) { + char str1[] = "Easy"; + char str2[] = "Medium"; + char str3[] = "hard"; + if (right_pb == 0) { + k++; + } + k = k % 3; + if(k == 1) { + uLCD.text_string(str1, 3, 3, FONT_7X8, GREEN); + } else { + uLCD.text_string(str1,3, 3, FONT_7X8, WHITE); + } + + if(k == 2) { + uLCD.text_string(str2, 3, 4, FONT_7X8, GREEN); + } else { + uLCD.text_string(str2, 3, 4, FONT_7X8, WHITE); + } + + if(k == 0) { + uLCD.text_string(str3, 3, 5, FONT_7X8, GREEN); + } else { + uLCD.text_string(str3, 3, 5, FONT_7X8, WHITE); + } + + if (fire_pb == 0) { + if (k == 0) { + current_player.current_level = 3; + } else { + current_player.current_level = k; + } + set_missile_speed(5 - current_player.current_level); + set_missile_interval(10 - current_player.current_level); + uLCD.text_string(str1, 3, 3, FONT_7X8, BACKGROUND_COLOR); + uLCD.text_string(str2, 3, 4, FONT_7X8, BACKGROUND_COLOR); + uLCD.text_string(str3, 3, 5, FONT_7X8, BACKGROUND_COLOR); + char go[] = "READY!"; + uLCD.text_string(go, 6, 6, FONT_7X8, GREEN); + wait(1.5); + uLCD.text_string(go, 6, 6, FONT_7X8, BACKGROUND_COLOR); + break; + } + + + } + /// 2.Begin the game loop while(1){ + char str[] = {'s', 'c', 'o', 'r', 'e', ':', '0' + current_player.score}; + char life_str[] = {'l','i','f', 'e',':', '0' + current_player.life}; + char level_str[] = {'l', 'e', 'v', 'e', 'l' ,':','0' + current_player.current_level}; + uLCD.text_string(str, 11, 0, FONT_7X8, WHITE); + uLCD.text_string(life_str, 0, 1, FONT_7X8, WHITE); + uLCD.text_string(level_str, 0, 0, FONT_7X8, GREEN); + + seg_driver(current_player.am_remain); /// 3.Example of drawing the player - player_draw(60,100); // draws a player at the center of the screen - + player_draw(); // draws a player at the center of the screen + draw_antimissiles(); /// 4.Example of calling the missile API. missile_generator(); /// It updates all incoming missiles on the screen + update_explosion(); + draw_explosion(); /// 5.Implement the code to get user input and update the player /// -[Hint] You could see city_landscape.cpp to get some ideas about how to implement your player. <br> if(left_pb == 0){ /// -[Hint] Implement the code to move player left <br> + player_move_left(); } if(right_pb == 0){ /// -[Hint] Implement the code to move player right <br> + player_move_right(); } if(fire_pb == 0){ /// -[Hint] Implement the code to fire player-missile <br> - + shoot(); // [Demo of play sound file] - playSound("/sd/wavfiles/BUZZER.wav"); + //playSound("/sd/wavfiles/BUZZER.wav"); } - + if(fouth_pb == 0 && current_player.protector_num > 0) { + current_player.protector.is_active = 1; + current_player.protector.timer = 0; + current_player.protector_num--; + } + update_protector(); + update_antimissile_positions(); + check_interception(); + check_city_destruction(); /// 6.Implement the code to draw a user missile /// -[Hint] You could see missile.cpp or missile_generator() for your reference <br> + if (current_player.score > 9 || (!left_pb && !right_pb)) { + advance_level(); + //display_victory(); + } else if(!is_any_left()) { + current_player.life--; + city_landscape_init(number_of_cities); + + } else if(current_player.current_level >= 4) { + display_victory(); + break; + } + if (current_player.life == 0) { + display_failure(); + break; + } + /// 7.Implement the code to detect the collision between missiles and cities /// -[Hint] You could use city_get_info() and missile_get_info() <br> /// -[Hint] You could use missile_set_exploded() to notify the missile module that the missile was exploded. <br> @@ -130,3 +225,106 @@ // close wav file fclose(wave_file); } + +void advance_level() { + current_player.current_level++; + set_missile_speed(5 - current_player.current_level); + set_missile_interval(10 - current_player.current_level); + city_landscape_init(4); + current_player.score = 0; + current_player.protector_num = 3; + char str[] = "Enter NEXT LEVEL"; + uLCD.text_string(str, 2, 6, FONT_7X8, WHITE); + wait(1); + uLCD.text_string(str, 2, 6, FONT_7X8, BACKGROUND_COLOR); + int i; + for (i = 0;i < MAX_NUM_MISSILE;i++) { + missile_set_exploded(i); + } +} +void check_interception() { + int i,j,k; + for (i = 0;i < MAX_NUM_MISSILE; i++) { + for (j = 0; j < current_player.max_am; j++) { + if (missile_record[i].status == MISSILE_ACTIVE && am[j].status == ACTIVE + && within_range(missile_record[i], am[j])) { + for (k = 0; k < current_player.max_am; k++) { + if (ex[k].exploded == NO) { + //find a unused explosion activate it + ex[k].x = am[j].x; + ex[k].y = am[j].y; + ex[k].exploded = YES; + ex[k].color = PLAYER_COLOR; + break; + } + } + //set both the missile and anti missile to DEACTIVE + missile_record[i].status = MISSILE_EXPLODED; + am[j].status = DEACTIVE; + current_player.am_remain++; + current_player.score++; + } + } + } + +} + +void check_city_destruction() { + int i,j,k; + for (i = 0; i < MAX_NUM_MISSILE; i++) { + for(j = 0;j < number_of_cities;j++) { + if (missile_record[i].status == MISSILE_ACTIVE && city_get_info(j).status == EXIST && check_destruction_range(missile_record[i], city_get_info(j))) { + for (k = 0; k < current_player.max_am; k++) { + if (ex[k].exploded == NO) { + //find a unused explosion activate it + ex[k].x = missile_record[i].x; + ex[k].y = missile_record[i].y; + ex[k].exploded = YES; + ex[k].color = LANDSCAPE_COLOR; + break; + } + } + missile_record[i].status = MISSILE_EXPLODED; + city_destroy(j); + } + } + } + + +} + +void display_victory() { + uLCD.cls(); + char str[] = "You Are Winnner"; + uLCD.text_string(str, 2, 9, FONT_7X8, WHITE); +} + +void display_failure() { + uLCD.cls(); + char str[] = "Game Over"; + uLCD.text_string(str, 3, 9, FONT_7X8, WHITE); +} + + + + +int check_destruction_range(MISSILE m,CITY c) { + if(c.x <= m.x + && m.x <= c.x + c.width + && c.y <= m.y + && m.y <= c.y + c.height) { + return 1; + } + return 0; +} + +int within_range(MISSILE m, ANTIMISSILE a) { + if(m.x - 2 <=a.x + && a.x <= m.x + 2 + && m.y - 2 <=a.y + && a.y <= m.y + 2) { + return 1; + } + return 0; +} +
--- a/missile/missile.cpp Wed Oct 29 02:58:53 2014 +0000 +++ b/missile/missile.cpp Mon Nov 17 13:15:34 2014 +0000 @@ -22,7 +22,7 @@ #include "missile_private.h" -MISSILE missile_record[MAX_NUM_MISSILE]; + int missile_tick=0; int missile_interval = 10; int missile_speed = 4; @@ -121,6 +121,13 @@ missile_record[i].status = MISSILE_DEACTIVE; //resets the missile's internal tick missile_record[i].tick = 0; + } + + if (missile_record[i].y > 128) { + //when the missile hit the ground + missile_draw(missile_record[i], BACKGROUND_COLOR); + missile_record[i].tick = 0; + missile_record[i].status = MISSILE_DEACTIVE; } }
--- a/missile/missile_public.h Wed Oct 29 02:58:53 2014 +0000 +++ b/missile/missile_public.h Mon Nov 17 13:15:34 2014 +0000 @@ -40,8 +40,11 @@ MISSILE_STATUS status; ///< The missile status, see MISSILE_STATUS } MISSILE; + #define MAX_NUM_MISSILE 5 +//MISSILE missile_record[MAX_NUM_MISSILE]; + /** This function draw the missiles onto the screen Call missile_generator() repeatedly in your game-loop. ex: main() */
--- a/player.cpp Wed Oct 29 02:58:53 2014 +0000 +++ b/player.cpp Mon Nov 17 13:15:34 2014 +0000 @@ -27,10 +27,187 @@ #include "player.h" // Example of drawing the player -void player_draw(int x, int y) { - uLCD.filled_rectangle(x, y, x+PLAYER_WIDTH, y+PLAYER_HEIGHT, PLAYER_COLOR); - uLCD.filled_rectangle(x+PLAYER_DELTA, y-PLAYER_DELTA, x+PLAYER_WIDTH-PLAYER_DELTA, y+PLAYER_HEIGHT, PLAYER_COLOR); + +void player_init() { + current_player.x = 60; + current_player.y = 100; + current_player.am_remain = 5; + current_player.max_am = 5; + current_player.status = PLAYER_ACTIVE; + current_player.score = 0; + current_player.current_level = 0; + current_player.life = 5;//inital 5 hp + current_player.protector_num = 3; +} + +void update_protector() { + if (current_player.protector.is_active) { + current_player.protector.timer++; + uLCD.line(0, 80, 128, 80, WHITE); + int i,k; + for (i = 0; i < MAX_NUM_MISSILE; i++) { + if (missile_record[i].status == MISSILE_ACTIVE && missile_record[i].y < 80) { + for (k = 0; k < current_player.max_am; k++) { + if (ex[k].exploded == NO) { + //find a unused explosion activate it + ex[k].x = missile_record[i].x; + ex[k].y = missile_record[i].y; + ex[k].exploded = YES; + ex[k].color = WHITE; + break; + } + } + missile_record[i].status = MISSILE_EXPLODED; + } + } + if (current_player.protector.timer == 10) { + current_player.protector.is_active = 0; + uLCD.line(0, 80, 128, 80, BACKGROUND_COLOR); + } + } +} + +void explosion_init() { + int i; + for (i = 0; i < current_player.max_am;i++) { + ex[i].x = 0; + ex[i].y = 0; + ex[i].tick = 0; + ex[i].radius = 3; + ex[i].exploded = NO; + ex[i].color = PLAYER_COLOR; + } +} + +void update_explosion() { + int i; + for (i = 0;i < current_player.max_am;i++) { + if (ex[i].exploded == YES) { + ex[i].tick++; + uLCD.circle(ex[i].x, ex[i].y, ex[i].radius - 2, BACKGROUND_COLOR); + uLCD.circle(ex[i].x, ex[i].y, ex[i].radius, BACKGROUND_COLOR); + draw_landscape(); + if (ex[i].tick <= 5) { + ex[i].radius = ex[i].radius + 2; + } else { + ex[i].tick = 0; + ex[i].radius = 0; + ex[i].exploded = NO; + } + } + } +} + +void draw_explosion() { + int i; + for (i = 0;i < current_player.max_am;i++) { + if (ex[i].exploded == YES) { + uLCD.circle(ex[i].x, ex[i].y, ex[i].radius - 2, ex[i].color); + uLCD.circle(ex[i].x, ex[i].y, ex[i].radius, ex[i].color); + } + } +} + +void antimissile_init() { + int i; + for (i = 0; i < current_player.max_am;i++) { + am[i].x = current_player.x; + am[i].y = current_player.y; + am[i].speed = 5; + am[i].tick = 0; + am[i].status = DEACTIVE; + } } +//(x,y) is the top left corner +void player_draw() { + int x = current_player.x; + int y = current_player.y; + uLCD.filled_rectangle(x - 5, y, x- 5 + PLAYER_WIDTH, y+PLAYER_HEIGHT, PLAYER_COLOR); + uLCD.line(x - 5, y - 3, x - 5, y + PLAYER_HEIGHT + 3, PLAYER_COLOR); + uLCD.line(x- 5 + PLAYER_WIDTH, y - 3, x- 5 + PLAYER_WIDTH, y + PLAYER_HEIGHT + 3, PLAYER_COLOR); + uLCD.line(x, y - 3, x, y + PLAYER_HEIGHT + 3, PLAYER_COLOR); + //uLCD.filled_rectangle(x+PLAYER_DELTA, y-PLAYER_DELTA, x+PLAYER_WIDTH-PLAYER_DELTA, y+PLAYER_HEIGHT, PLAYER_COLOR); +} + +void player_move_left() { + int x = current_player.x; + int y = current_player.y; + uLCD.filled_rectangle(x - 5, y, x- 5 + PLAYER_WIDTH, y+PLAYER_HEIGHT, BACKGROUND_COLOR); + uLCD.line(x - 5, y - 3, x - 5, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + uLCD.line(x- 5 + PLAYER_WIDTH, y - 3, x- 5 + PLAYER_WIDTH, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + uLCD.line(x, y - 3, x, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + if (current_player.x - PLAYER_DELTA > 0) { + current_player.x = current_player.x - PLAYER_DELTA; + } +} + +void player_move_right() { + int x = current_player.x; + int y = current_player.y; + uLCD.filled_rectangle(x - 5, y, x- 5 + PLAYER_WIDTH, y+PLAYER_HEIGHT, BACKGROUND_COLOR); + uLCD.line(x - 5, y - 3, x - 5, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + uLCD.line(x- 5 + PLAYER_WIDTH, y - 3, x- 5 + PLAYER_WIDTH, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + uLCD.line(x, y - 3, x, y + PLAYER_HEIGHT + 3, BACKGROUND_COLOR); + if(current_player.x + PLAYER_DELTA < 126) { + current_player.x = current_player.x + PLAYER_DELTA; + } +} + +PLAYER get_player_info() { + return current_player; +} + +//find a available antimissile and set it active +void shoot() { + int i; + if (current_player.am_remain > 0) { + for(i = 0; i < current_player.max_am; i++) { + if (am[i].status == DEACTIVE) { + am[i].status = ACTIVE; + am[i].x = current_player.x; + am[i].y = current_player.y; + am[i].speed = 5; // need to be improved + am[i].tick = 0; + current_player.am_remain--; + break; + } + } + } +} +//update all active missiles position +void update_antimissile_positions() { + int i, rate; + for(i = 0; i < current_player.max_am;i++) { + if(am[i].status == ACTIVE) { + am[i].tick++; + rate = 5 / am[i].speed; + if (am[i].y - 2 <= 0) { + //when the missile flies out of the screen + am[i].status = DEACTIVE; + uLCD.line(am[i].x, am[i].y, am[i].x, am[i].y - 2, BACKGROUND_COLOR); + am[i].y = current_player.y; + am[i].x = current_player.x; + current_player.am_remain++; + + } else if (am[i].tick % rate == 0) { + uLCD.line(am[i].x, am[i].y, am[i].x, am[i].y - 2, BACKGROUND_COLOR); + am[i].y = am[i].y - 2; + } + + } + } +} +//find all active antimissiles and draw their current position +void draw_antimissiles() { + int i; + for(i = 0; i < current_player.max_am;i++) { + if (am[i].status == ACTIVE ) { + uLCD.line(am[i].x, am[i].y, am[i].x, am[i].y - 2, PLAYER_COLOR); + } + } +} + + // ... You need to implement your own functions for player ...
--- a/player.h Wed Oct 29 02:58:53 2014 +0000 +++ b/player.h Mon Nov 17 13:15:34 2014 +0000 @@ -31,11 +31,85 @@ #define PLAYER_COLOR 0x0000FF -/** Get the information of city +typedef enum { + PLAYER_ACTIVE = 1, + PLAYER_DIED = 0 +} PLAYER_STATUS; + + +typedef struct { + int timer; + int is_active; +} PROTECTOR; + +typedef struct { + int x;// the current x of the player, bottom left + int y;//current y position of the player, bottom left point + int max_am; + int am_remain;//how many missile for the player remain + int life;//his hp remain + int current_level; + PLAYER_STATUS status;//if he is dead + int score;//# of interceptions + int protector_num;// number of protector left + PROTECTOR protector; +} PLAYER; +/** et the information of city @brief x and y are the top left corner of the player drawing @param x x-coordinate @param y y-coordinate */ -void player_draw(int x, int y); + + + +typedef enum { + DEACTIVE = 0, + ACTIVE = 1, + //MISSLE_EXPLODE = 2 +} ANTIMISSLE_STATUS; + +typedef struct { + int x; + int y; + int speed; + int tick; //anti missile's internal clock + ANTIMISSLE_STATUS status; +} ANTIMISSILE; + +typedef enum{ + YES = 1, + NO = 0 +} EXPLOSION_STATUS; +typedef struct{ + int x; + int y; + int tick; + int radius; + EXPLOSION_STATUS exploded; + int color; +} EXPLOSION; + + +//initialize the player for the game +void player_init(); +void player_draw(); +void player_move_left(); +void player_move_right(); +void antimissile_init(); +void shoot(); +void update_antimissile_positions(); +void draw_antimissiles(); +void explosion_init(); +void update_explosion(); +void draw_explosion(); +void update_protector();// update protector status and draw it on the screen + +//extern PLAYER current_player; +//extern ANTIMISSILE am[5]; +//extern EXPLOSION ex[5]; +/** +get the currrent player info +*/ +PLAYER get_player_info(); #endif //PLAYER_H \ No newline at end of file