Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407
Dependencies: Joystick N5110 SDFileSystem mbed
Diff: main.cpp
- Revision:
- 6:89d4a7f7588b
- Parent:
- 5:34855f712350
- Child:
- 7:babc367a3333
diff -r 34855f712350 -r 89d4a7f7588b main.cpp --- a/main.cpp Wed Apr 27 00:19:52 2016 +0000 +++ b/main.cpp Thu Apr 28 14:14:54 2016 +0000 @@ -135,7 +135,7 @@ AnalogIn* y_axis_; InterruptIn* button_; - //Ticker to prevent joystick button bounce + //Timeout to prevent joystick button bounce Timeout* button_debounce_; //Stores X and Y offsets @@ -178,6 +178,7 @@ //Timeout Timeout joystick_cursor_regulator; //Stops the cursor from jumping +Timeout shoot_button_debounce; //Stops the cannon from firing when transitioning from a menu to the game //Buffer holding pixel data of screen with point representations int screen_buffer[84][48]; @@ -203,13 +204,13 @@ int fsm_state = 0; //Stores the state for menu fsm's int cursor_y_pos = 0; //Stores the cursor position //Cannon related integers +int number_of_lives = 3; int cannon_xpos = 24; const int cannon_ypos = 43; -int number_of_lives = 3; //Cannon missile related integers int cannon_missile_x_pos = 28; int cannon_missile_y_pos = 40; -//Invader related integers +//Invader related integers int no_of_alive_invaders = 15; //Invader missile related integers int invader_strong_missile_x_pos; @@ -222,7 +223,7 @@ enum Status {dead, dying, alive}; //Contains the status of invaders enum Invader {small, medium, large, none}; //Contains the type of invader passed into //Contains the current state of the game -enum GameState {menu, game, paused, save, load}; +enum GameState {menu, game, paused, save, load, scores, settings}; GameState game_state = menu; //Bit-maps @@ -356,12 +357,18 @@ bool before_bitmap[8][14]; bool after_bitmap[8][14]; } barrier[3]; -//FSM for paused menu -struct FSMPaused { +//FSM for menus +struct FSMMenus { GameState output; int next_state[2]; }; -FSMPaused fsm_paused[3] = { +FSMMenus fsm_main_menu[4] = { + {game, {1, 3}}, + {load, {2, 0}}, + {scores, {3, 1}}, + {settings, {0, 2}} +}; +FSMMenus fsm_paused[3] = { //Pause menu FSM {game, {1, 2}}, {save, {2, 0}}, {menu, {0, 1}} @@ -376,6 +383,7 @@ volatile bool g_move_invader_normal_missile_flag[2] = {false, false}; volatile bool g_cannon_hit_flag = false; volatile bool g_joystick_cursor_regulator_flag = false; +volatile bool g_shoot_button_debounce_flag = false; // function prototypes // error function hangs flashing an LED @@ -430,6 +438,10 @@ void CollisionDetectionInvaderNormalMissile(int missile_no); void DetachTickers(); void AttachTickers(); +//Pause Menu Functions +void PauseScreen(); +void PrintPauseScreen(); +void MoveCursor(const struct FSMMenus *fsm); //void InitUFO(); void DrawUFO(); //ISR's @@ -440,6 +452,7 @@ void move_cannon_missile_isr(); void cannon_hit_isr(); void joystick_cursor_regulator_isr(); +void shoot_button_debounce_isr(); //Function pointer to move invader normal missile isr void (*move_invader_normal_missile_isr[2])(); void move_invader_normal_missile_0_isr(); @@ -468,76 +481,78 @@ //Samples joystick every 0.05 second move_joystick.attach(&move_joystick_isr, 0.05); + + while (true) { if (game_state == menu) { //Menu screen lcd.clear(); - lcd.printString("Menu", 0, 1); + fsm_state = 0; //Sets the fsm state to 0 + while (game_state == menu) { + lcd.printString("Space Invaders", 0, 0); + lcd.printString("Menu", 28, 1); + lcd.drawLine(0, 15, 83, 15, 2); + + lcd.printString("New Game", 5, 2); + lcd.printString("Load Game", 5, 3); + lcd.printString("High Scores", 5, 4); + lcd.printString("Settings", 5, 5); + + //Draws the cursor + cursor_y_pos = ((fsm_state+2)*8)+3; //Adds 2 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3 + lcd.drawRect(74, cursor_y_pos, 2, 2, 1); + + if (g_move_joystick_flag) { + g_move_joystick_flag = false; + + //Moves the cursor to match the selected option, only if the joystick isn't centred + MoveCursor(fsm_main_menu); + } + + if (g_shoot_pressed_flag) { + g_shoot_pressed_flag = false; + + game_state = fsm_main_menu[fsm_state].output; - if(joystick.get_button_flag()) { - joystick.set_button_flag(0); - - //Clears the screen buffer and initalises the game - memset(screen_buffer, 0, sizeof(screen_buffer)); - no_of_alive_invaders = 15; - score = 0; - number_of_lives = 3; - InitSmallInvaders(); - InitMediumInvaders(); - InitLargeInvaders(); - InitBarriers(); + //If the game state is equal to the game initalise it + if (game_state == game) { + //Clears the screen buffer and runs init functions + memset(screen_buffer, 0, sizeof(screen_buffer)); + no_of_alive_invaders = 15; + score = 0; + number_of_lives = 3; + InitSmallInvaders(); + InitMediumInvaders(); + InitLargeInvaders(); + InitBarriers(); + //Sets the flags so enemies pop up straight away + g_update_screen_flag = true; + g_move_joystick_flag = true; + g_move_enemies_flag = true; + //Forces the missiles to have the fired flags to flase + cannon_missile_on_screen = false; + invader_normal_missile[0].fired = false; + invader_normal_missile[1].fired = false; + } + } - game_state = game; + if(joystick.get_button_flag()) { + joystick.set_button_flag(0); + } + + lcd.refresh(); + sleep(); } } else if (game_state == paused) { //Paused screen - //Prints paused and a line underneath - lcd.printString("Paused", 24, 0); - lcd.drawLine(0, 7, 83, 7, 2); - //Displays the current score - char buffer[14]; - sprintf(buffer, "Score: %d", score); - lcd.printString(buffer, 0, 1); - //Displays the no of lives - sprintf(buffer, "Lives: %d", number_of_lives); - lcd.printString(buffer, 0, 2); - lcd.drawLine(0, 23, 83, 23, 2); - //Prints options on pause menu - lcd.printString("Resume", 10, 3); - lcd.printString("Save", 10, 4); - lcd.printString("Quit", 10, 5); - - //Draws the cursor - cursor_y_pos = ((fsm_state+3)*8)+3; //Adds 3 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3 - lcd.drawRect(64, cursor_y_pos, 2, 2, 1); - - if (g_move_joystick_flag) { - g_move_joystick_flag = false; - - //If the joystick is is pushed down half way clear the cursor and set the next state - if (joystick.GetYValue() < 0.25f) { - //Clears the cursor - lcd.drawRect(64, cursor_y_pos, 2, 2, 2); - //Sets the new state - fsm_state = fsm_paused[fsm_state].next_state[0]; - } else if (joystick.GetYValue() > 0.75f) { - //Clears the cursor - lcd.drawRect(64, cursor_y_pos, 2, 2, 2); - //Sets the new state - fsm_state = fsm_paused[fsm_state].next_state[1]; - } - } - - if (g_shoot_pressed_flag) { - g_shoot_pressed_flag = false; - game_state = fsm_paused[fsm_state].output; - } - + //Clears the screen + lcd.clear(); + //Resets the fsm state to 0 + fsm_state = 0; + PauseScreen(); } else if (game_state == game) { //Game screen - AttachTickers(); Game(); } - pc.printf("P: %d\n", g_shoot_pressed_flag); sleep(); } } @@ -596,8 +611,14 @@ void shoot_pressed_isr() { - g_shoot_pressed_flag = true; - pc.printf("B\n"); + //Only sets the shoot pressed flag 0.1s after the last press + if (!g_shoot_button_debounce_flag) { + g_shoot_pressed_flag = true; + g_shoot_button_debounce_flag = true; + + //Attaches a timeout to clear the debounce flag 0.125 seconds after it was set + shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125); + } } void move_cannon_missile_isr() @@ -611,19 +632,25 @@ if (game_state == game) { g_move_joystick_flag = true; } else if (!g_joystick_cursor_regulator_flag) { - //Only sets the flag if the regulator is not set + //Only sets the flag if the regulator is not set g_move_joystick_flag = true; g_joystick_cursor_regulator_flag = true; - //Attachs a timeout to clear the regulator in 0.2s to prevent the cursor from behaving erratically - joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.125); + //Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically + joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.1); } } -void joystick_cursor_regulator_isr() { +void joystick_cursor_regulator_isr() +{ g_joystick_cursor_regulator_flag = false; } +void shoot_button_debounce_isr() +{ + g_shoot_button_debounce_flag = false; +} + void move_invader_normal_missile_0_isr() { g_move_invader_normal_missile_flag[0] = true; @@ -640,9 +667,8 @@ } void Game() -{ +{ //Stays within the loop while the selected state is game - pc.printf("G: %d\n", g_shoot_pressed_flag); while (game_state == game) { //If the game is over detach all the tickers if (number_of_lives == 0) { @@ -737,15 +763,8 @@ if (joystick.get_button_flag()) { joystick.set_button_flag(0); - //Clears the screen - lcd.clear(); - - //Resets the fsm state to 0 - fsm_state = 0; - //Detach all game tickers DetachTickers(); - game_state = paused; } } @@ -754,7 +773,6 @@ } } - void UpdateScreen() { //Loops through the screen buffer and sets pixels on the LCD @@ -1290,13 +1308,12 @@ g_cannon_hit_flag = true; //Detaches all tickers DetachTickers(); - //Creates a Ticker object on the stack with a period of 2 seconds to pause the game for 2 seconds - Ticker cannon_hit; + //Creates a Timeout object on the stack with a period of 2 seconds to pause the game for 2 seconds + Timeout cannon_hit; cannon_hit.attach(&cannon_hit_isr, 2); while (g_cannon_hit_flag) { sleep(); } - cannon_hit.detach(); AttachTickers(); --number_of_lives; invader_normal_missile[missile_no].fired = false; @@ -1442,4 +1459,72 @@ move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05); } } +} + +void PauseScreen() +{ + while (game_state == paused) { + //Prints the pause screen, score etc + PrintPauseScreen(); + + //Draws the cursor + cursor_y_pos = ((fsm_state+3)*8)+3; //Adds 3 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3 + lcd.drawRect(74, cursor_y_pos, 2, 2, 1); //Draws the cursor + + if (g_move_joystick_flag) { + g_move_joystick_flag = false; + + //Moves the cursor to match the selected option, only if the joystick isn't centred + MoveCursor(fsm_paused); + } + + //If the button is pressed the selected option will appear on the screen + if (g_shoot_pressed_flag) { + g_shoot_pressed_flag = false; + game_state = fsm_paused[fsm_state].output; + } + + //Resets the joystick flag to false if pressed + if (joystick.get_button_flag()) { + joystick.set_button_flag(0); + } + + lcd.refresh(); + + sleep(); + } +} + +void PrintPauseScreen() +{ + //Prints paused and a line underneath + lcd.printString("Paused", 24, 0); + //Displays the current score + char buffer[14]; + sprintf(buffer, "Score: %d", score); + lcd.printString(buffer, 0, 1); + //Displays the no of lives + sprintf(buffer, "Lives: %d", number_of_lives); + lcd.printString(buffer, 0, 2); + lcd.drawLine(0, 23, 83, 23, 2); + //Prints options on pause menu + lcd.printString("Resume", 5, 3); + lcd.printString("Save", 5, 4); + lcd.printString("Quit", 5, 5); +} + +void MoveCursor(const struct FSMMenus *fsm) +{ + //If the joystick is is pushed down half way clear the cursor and set the next state + if (joystick.GetYValue() < 0.25f) { + //Clears the cursor + lcd.drawRect(74, cursor_y_pos, 2, 2, 2); + //Sets the new state + fsm_state = fsm[fsm_state].next_state[0]; + } else if (joystick.GetYValue() > 0.75f) { + //Clears the cursor + lcd.drawRect(74, cursor_y_pos, 2, 2, 2); + //Sets the new state + fsm_state = fsm[fsm_state].next_state[1]; + } } \ No newline at end of file