Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407
Dependencies: Joystick N5110 SDFileSystem mbed
Diff: main.cpp
- Revision:
- 7:babc367a3333
- Parent:
- 6:89d4a7f7588b
- Child:
- 8:b2faec20ed8f
diff -r 89d4a7f7588b -r babc367a3333 main.cpp --- a/main.cpp Thu Apr 28 14:14:54 2016 +0000 +++ b/main.cpp Mon May 02 16:28:07 2016 +0000 @@ -6,457 +6,11 @@ - Core cannon is drawn and can move, enemies are visible and they switch between states every second Week 21 - Begun to set up barriers Easter - Barriers work, invader and player can shoot. Begun setting up menus +Week 22 - Most menus work +Week 23 - Menus work */ #include "mbed.h" -#include "N5110.h" - -//Direction invaders are travelling -#define LEFT 0 -#define RIGHT 1 - -//Joystick Class -class Joystick -{ -public: - //Constructor - Joystick(PinName x_axis_pin, PinName y_axis_pin, PinName button_pin) { - //Dynamically allocates the pins and button debounce ticker - x_axis_ = new AnalogIn(x_axis_pin); - y_axis_ = new AnalogIn(y_axis_pin); - button_ = new InterruptIn(button_pin); - button_debounce_ = new Timeout(); - } - - //Deconstructor - ~Joystick() { - //Clears all dynamically allocated memory - delete x_axis_; - delete y_axis_; - delete button_; - delete button_debounce_; - } - - //Initalises the Joystick - //Sets up the ISRs and grabs the offsets for each axis - void init() { - //Sets up the button ISR - button_->mode(PullDown); - button_->rise(this, &Joystick::button_isr); - - //Initalises the vairables and flags - x_offset_ = 0; - y_offset_ = 0; - g_button_flag_ = false; - g_button_debounce_flag_ = false; - - //Samples the joystick 5 times and takes an average to get the offset - float x_sum = 0; - float y_sum = 0; - - for (int i = 0; i < 5; ++i) { - x_sum += x_axis_->read(); - y_sum += y_axis_->read(); - } - - x_offset_ = 0.5f - x_sum/5.0f; - y_offset_ = 0.5f - y_sum/5.0f; - } - - //Take 5 readings and returns the average measurement, accounting for joystick offset x and y values - float GetXValue() { - - float x_sum = 0; - - for (int i = 0; i < 5; ++i) { - x_sum += x_axis_->read(); - } - - float x_value = x_sum/5.0f + x_offset_; - - //Caps the value for the POT between 0 and 1 - if (x_value < 0.0f) { - return 0; - } else if (x_value > 1.0f) { - return 1; - } else { - return x_value; - } - } - - float GetYValue() { - - float y_sum = 0; - - for (int i = 0; i < 5; ++i) { - y_sum += y_axis_->read(); - } - - float y_value = y_sum/5.0f + y_offset_; - - //Caps the value for the POT between 0 and 1 - if (y_value < 0.0f) { - return 0; - } else if (y_value > 1.0f) { - return 1; - } else { - return y_value; - } - } - - //Getter and setters for flags - int get_button_flag() { - return g_button_flag_; - } - - void set_button_flag(int value) { - g_button_flag_ = value; - } - -private: - //Button ISR Method - void button_isr() { - if (!g_button_debounce_flag_) { - g_button_flag_ = true; - g_button_debounce_flag_ = true; - - //Sets up the debounce ticker - button_debounce_->attach(this, &Joystick::button_debounce_isr, 0.2); - } - } - - //Button debounce ISR method - void button_debounce_isr() { - g_button_debounce_flag_ = false; - } - -private: - //Pin inputs - AnalogIn* x_axis_; - AnalogIn* y_axis_; - InterruptIn* button_; - - //Timeout to prevent joystick button bounce - Timeout* button_debounce_; - - //Stores X and Y offsets - float x_offset_; - float y_offset_; - - //Stores interrupt flags - volatile bool g_button_flag_; - volatile bool g_button_debounce_flag_; -}; - -// K64F on-board LEDs -DigitalOut r_led(LED_RED); -DigitalOut g_led(LED_GREEN); -DigitalOut b_led(LED_BLUE); - -// K64F on-board switches -InterruptIn sw2(SW2); -InterruptIn sw3(SW3); - -// UART connection for PC -Serial pc(USBTX,USBRX); - -//Joystick -Joystick joystick(PTB3, PTB2, PTB11); - -//Shoot button -InterruptIn shoot_button(PTB18); - -//LCD object -// VCC, SCE, RST, D/C, MOSI, SCLK, LED -N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3); - -//Tickers -Ticker update_screen; -Ticker move_joystick; -Ticker move_cannon_missile; -Ticker move_enemies; -Ticker move_invader_normal_missile[2]; - -//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]; -const int empty_pixel = 0; -const int cannon_pixel = 1; -const int first_barrier_pixel = 2; -const int first_large_invader_pixel = 5; -const int first_medium_invader_pixel = 10; -const int first_small_invader_pixel = 15; -const int ufo_pixel = 20; -const int cannon_missile_pixel = 21; -const int invader_normal_missile_pixel = 22; - -//Booleans -//Invader related bools -bool invaders_in_state2 = true; -bool invader_direction = RIGHT; -//Cannon missile bool -bool cannon_missile_on_screen = false; - -//Integers -int score = 0; //Stores the score -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; -//Cannon missile related integers -int cannon_missile_x_pos = 28; -int cannon_missile_y_pos = 40; -//Invader related integers -int no_of_alive_invaders = 15; -//Invader missile related integers -int invader_strong_missile_x_pos; -int invader_strong_missile_y_pos; - -//Floats -float ticker_period = 1; //Stores the period of the invader move ticker - -//Enums -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, scores, settings}; -GameState game_state = menu; - -//Bit-maps -//Cannon bit-map -const bool cannon_bitmap[5][9] = { - {0, 0, 0, 0, 1, 0, 0, 0, 0}, - {0, 0, 0, 1, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 1, 1, 1, 1, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1} -}; -//Bitmaps for small invaders -const bool small_invader_bitmap_1[6][8] = { //First state - {0, 0, 0, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 1, 1, 1, 0}, - {1, 1, 0, 1, 1, 0, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1}, - {0, 1, 0, 1, 1, 0, 1, 0}, - {1, 0, 1, 0, 0, 1, 0, 1} -}; -const bool small_invader_bitmap_2[6][8] = { //Second state - {0, 0, 0, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 1, 1, 1, 0}, - {1, 1, 0, 1, 1, 0, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0, 0, 0, 1}, - {0, 1, 0, 0, 0, 0, 1, 0} -}; -//Bitmaps for medium invaders -const bool medium_invader_bitmap_1[6][10] = { //First state - {1, 0, 0, 1, 0, 0, 1, 0, 0, 1}, - {1, 0, 1, 1, 1, 1, 1, 1, 0, 1}, - {1, 1, 1, 0, 1, 1, 0, 1, 1, 1}, - {0, 1, 1, 1, 1, 1, 1, 1, 1, 0}, - {0, 0, 1, 0, 0, 0, 0, 1, 0, 0}, - {0, 1, 0, 0, 0, 0, 0, 0, 1, 0} -}; -const bool medium_invader_bitmap_2[6][10] = { //Second state - {0, 0, 0, 1, 0, 0, 1, 0, 0, 0}, - {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, - {0, 1, 1, 0, 1, 1, 0, 1, 1, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 0, 1, 0, 0, 0, 0, 1, 0, 1}, - {0, 0, 0, 1, 1, 1, 1, 0, 0, 0} -}; -//Bitmaps for large invaders -const bool large_invader_bitmap_1[6][12] = { //First state - {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, - {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0}, - {0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0} -}; -const bool large_invader_bitmap_2[6][12] = { //Second state - {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0}, - {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, - {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0}, - {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1} -}; -//Normal invader missile bitmap -const bool invader_normal_missile_bitmap[4][3] = { - {0, 1, 0}, - {1, 1, 1}, - {0, 1, 0}, - {0, 1, 0} -}; -//Strong invader missile bitmap -const bool invader_strong_missile_bitmap_1[4][3] = { //First state - {0, 0, 1}, - {0, 1, 0}, - {1, 0, 0}, - {0, 1, 0} -}; -const bool invader_strong_missile_bitmap_2[4][3] = { //Second state - {0, 1, 0}, - {1, 0, 0}, - {0, 1, 0}, - {0, 1, 1} -}; -//Barrier bitmap -const bool barrier_bitmap[8][14] = { - {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, - {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, - {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, - {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1} -}; -//Cannon barrier damage bitmap -const bool barrier_cannon_missile_damage_bitmap[3][3] = { - {0, 1, 0}, - {1, 0, 0}, - {1, 0, 1} -}; -//Normal invader barrier damage bitmap -const bool barrier_invader_normal_missile_damage_bitmap[2][3] = { - {1, 0, 1}, - {0, 1, 0} -}; -//UFO Bitmap -const bool ufo_bitmap[5][14] = { - {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0}, - {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, - {0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0} -}; - -//Structs -//Contains invader data -struct Invaders { - int x_pos; - int y_pos; - enum Status status; -} small_invader[5], medium_invader[5], large_invader[5]; //Five of each invader -//Contains data for Invader normal missiles -struct InvaderNormalMissiles { - int x_pos; - int y_pos; - bool fired; -} invader_normal_missile[2]; -//Contains data for barriers -struct Barriers { - int x_pos; - int y_pos; - bool before_bitmap[8][14]; - bool after_bitmap[8][14]; -} barrier[3]; -//FSM for menus -struct FSMMenus { - GameState output; - int next_state[2]; -}; -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}} -}; - -//ISR Flags -volatile bool g_update_screen_flag = true; -volatile bool g_move_joystick_flag = true; -volatile bool g_move_enemies_flag = true; -volatile bool g_shoot_pressed_flag = false; -volatile bool g_move_cannon_missile_flag = false; -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 -void error(); -// setup serial port -void init_serial(); -// set-up the on-board LEDs and switches -void init_K64F(); -//Init shoot button -void init_shoot(); -//Init Random Number Generator -void init_rng(); -// Added functions -void InitaliseGame(); -void Game(); -void UpdateScreen(); -void MoveCannon(); -void InitSmallInvaders(); -void ClearSmallInvaders(); -void ClearSingleSmallInvader(int invader_no); -void DrawSmallInvaders(); -void DrawSingleSmallInvader(int invader_no); -void InitMediumInvaders(); -void ClearMediumInvaders(); -void ClearSingleMediumInvader(int invader_no); -void DrawMediumInvaders(); -void DrawSingleMediumInvader(int invader_no); -void InitLargeInvaders(); -void ClearLargeInvaders(); -void ClearSingleLargeInvader(int invader_no); -void DrawLargeInvaders(); -void DrawSingleLargeInvader(int invader_no); -void InitBarriers(); -void DrawBarriers(); -void MoveInvaderXPositions(); -int CalculateInvaderLeftLimit(); -int CalculateInvaderRightLimit(); -void MoveInvadersLeft(int limit); -void MoveInvadersRight(int limit); -void MoveInvaderYPositions(bool new_direction); -Invader CalculateInvaderYLimit(); -Invader LowestInvaderInColumn(int column); -void FireCannonMissile(); -void MoveCannonMissile(); -void CollisionDetectionCannonMissile(); -int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]); -void CannonMissileHitBarrier(int first_pixel, int row); -void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile)); -void AttemptToFireInvaderNormalMissiles(); -void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader)); -void MoveInvaderNormalMissile(int missile_no); -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 -void update_screen_isr(); -void move_joystick_isr(); -void move_enemies_isr(); -void shoot_pressed_isr(); -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(); -void move_invader_normal_missile_1_isr(); +#include "main.h" int row_no = 5; int col_no = 14; @@ -515,23 +69,7 @@ //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; + InitaliseGame(); } } @@ -589,8 +127,8 @@ //Seeds the random number generator with noise from an analog in pin void init_rng() { - AnalogIn rng_seed(PTC10); - srand(floor(10000*rng_seed.read())); + AnalogIn rng_seed(PTC10); //Creates a AnalogIn on a unused pin + srand(floor(10000*rng_seed.read())); //Sets the seed as 10000x the input of the analog in } void init_shoot() @@ -676,6 +214,9 @@ lcd.clear(); lcd.printString("Game Over.", 1, 2); + char buffer[14]; + sprintf(buffer, "Score: %d", score); + lcd.printString(buffer, 1, 3); } else if (no_of_alive_invaders == 0) { //If the player wins a round //Resets the no of alive invaders no_of_alive_invaders = 15; @@ -773,6 +314,27 @@ } } +void InitaliseGame() +{ + //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; +} + void UpdateScreen() { //Loops through the screen buffer and sets pixels on the LCD @@ -791,7 +353,7 @@ void MoveCannon() { - //Clears the ship + //Clears the cannon for (int col = 0; col < 9; ++col) { for (int row = 0; row < 5; ++row) { if(cannon_bitmap[row][col]) { @@ -800,7 +362,7 @@ } } - //Changes the position of the ship when the joystick is moved, capping at 0 and 75 so it always fits on the screen + //Changes the position of the cannon when the joystick is moved, capping at 0 and 75 so it always fits on the screen if (joystick.GetXValue() < 0.25f) { cannon_xpos--; if (cannon_xpos < 0) { @@ -813,7 +375,7 @@ } } - //Redraws the ship + //Redraws the cannon for (int col = 0; col < 9; ++col) { for (int row = 0; row < 5; ++row) { if(cannon_bitmap[row][col]) { @@ -823,11 +385,11 @@ } } -//Sets the position and aliveness of the small invaders +//Sets the position and status of the small invaders void InitSmallInvaders() { for (int i = 0; i < 5; ++i) { - small_invader[i].x_pos = 2 + (i*13); + small_invader[i].x_pos = 2 + (i*13); // Large invaders are 12 across so add 13 for a gap space small_invader[i].y_pos = 1; small_invader[i].status = alive; } @@ -863,6 +425,7 @@ small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive; } +//Cycles through all the small invaders. If they're alive set them in the screen buffer void DrawSmallInvaders() { for (int i = 0; i < 5; ++i) { @@ -894,12 +457,13 @@ void InitMediumInvaders() { for (int i = 0; i < 5; ++i) { - medium_invader[i].x_pos = 1 + (i*13); + medium_invader[i].x_pos = 1 + (i*13); // Large invaders are 12 across so add 13 for a gap space medium_invader[i].y_pos = 8; medium_invader[i].status = alive; } } +//Cycles through all the medium invaders. If they're not already dead clear them void ClearMediumInvaders() { for (int i = 0; i < 5; ++i) { @@ -909,6 +473,7 @@ } } +//Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0 void ClearSingleMediumInvader(int invader_no) { for (int col = 0; col < 10; ++col) { @@ -928,6 +493,7 @@ medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive; } +//Cycles through all the medium invaders. If they're alive set them in the screen buffer void DrawMediumInvaders() { for (int i = 0; i < 5; ++i) { @@ -937,6 +503,7 @@ } } +//Cycles through the the screen invader bitmap and sets the pixels in the buffer void DrawSingleMediumInvader(int invader_no) { for (int col = 0; col < 10; ++col) { @@ -954,7 +521,7 @@ } } -//Sets the position and aliveness of the large invaders +//Sets the position and status of the large invaders void InitLargeInvaders() { for (int i = 0; i < 5; ++i) { @@ -964,6 +531,7 @@ } } +//Cycles through all the large invaders. If they're not already dead clear them void ClearLargeInvaders() { for (int i = 0; i < 5; ++i) { @@ -993,6 +561,7 @@ large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive; } +//Cycles through all the large invaders. If they're alive set them in the screen buffer void DrawLargeInvaders() { for (int i = 0; i < 5; ++i) { @@ -1002,6 +571,7 @@ } } +//Cycles through the the screen invader bitmap and sets the pixels in the buffer void DrawSingleLargeInvader(int invader_no) { for (int col = 0; col < 12; ++col) { @@ -1019,6 +589,7 @@ } } +//Sets the position and loads the bitmap into the barrier objects void InitBarriers() { for (int i = 0; i < 3; ++i) { @@ -1051,21 +622,20 @@ void MoveInvaderXPositions() { - //Checks the left limit - int left_invader_limit = CalculateInvaderLeftLimit(); - - //Checking the right limit - int right_invader_limit = CalculateInvaderRightLimit(); - - //End of block + //Moves the invader in the current direction if (invader_direction == RIGHT) { + //Checking the right limit + int right_invader_limit = CalculateInvaderRightLimit(); MoveInvadersRight(right_invader_limit); } else { - //Checks the first large invader to see if it can travel anymore + //Checks the left limit + int left_invader_limit = CalculateInvaderLeftLimit(); MoveInvadersLeft(left_invader_limit); } } +//Checks the status off the invaders per column, starting from the left +//If they're alive return the row number int CalculateInvaderLeftLimit() { for (int i = 0; i < 5; ++i) { @@ -1078,6 +648,8 @@ return 4; } +//Checks the status off the invaders per column, starting from the right +//If they're alive return the row number int CalculateInvaderRightLimit() { for (int i = 4; i >= 0; --i) { @@ -1095,6 +667,7 @@ //Checks the first large invader to see if it can travel anymore if (large_invader[limit].x_pos > 1) { for (int i = 0; i < 5; ++i) { + //Moves the invaders 2 to the left small_invader[i].x_pos -= 2; medium_invader[i].x_pos -= 2; large_invader[i].x_pos -= 2; @@ -1109,6 +682,7 @@ { //Checks the first large invader to see if it can travel anymore if (large_invader[limit].x_pos < 71) { + //Moves the invaders 2 to the right for (int i = 0; i < 5; ++i) { small_invader[i].x_pos += 2; medium_invader[i].x_pos += 2; @@ -1192,11 +766,14 @@ void FireCannonMissile() { + //Sets the cannon fired flag to true cannon_missile_on_screen = true; - //Add 4 to cannon x_pos to get shot x_pos + //Offset cannon missile x position by 4 of the cannons x pos cannon_missile_x_pos = cannon_xpos + 4; + //Will always have a starting y of 40 cannon_missile_y_pos = 40; + //Attach the move cannon missile move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); } @@ -1227,65 +804,37 @@ } } -void MoveInvaderNormalMissile(int missile_no) -{ - //Checks missile will not exceed screen buffer - if (invader_normal_missile[missile_no].y_pos < 44) { - //Loops through the bitmap and clears the missile from the screen buffer - for (int col = 0; col < 3; ++col) { - for (int row = 0; row < 4; ++row) { - if (invader_normal_missile_bitmap[row][col]) { - screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel; - } - } - } - - //Increments the position of the missile - ++invader_normal_missile[missile_no].y_pos; - - //Collision detection - CollisionDetectionInvaderNormalMissile(missile_no); - - } else { - //Loops through the bitmap and clears the pixels still on the screen - for (int col = 0; col < 3; ++col) { - for (int row = 0; row < 4; ++row) { - if (invader_normal_missile_bitmap[row][col]) { - screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel; - } - } - } - - invader_normal_missile[missile_no].fired = false; - move_invader_normal_missile[missile_no].detach(); - } -} - //Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer void CollisionDetectionCannonMissile() { for (int row = 0; row < 4; ++row) { int object_no; - if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_small_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_small_invader_pixel + 5)) { //Collides with a small invader + int pixel_check = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row]; + pc.printf("Pixel check: %d\n", pixel_check); + if (pixel_check >= first_small_invader_pixel && pixel_check < ufo_pixel) { //Collides with a small invader + //Find the object no of the small invader it hit, clears it and increments the score object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader); ClearSingleSmallInvader(object_no); score += 40; break; - } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_medium_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_medium_invader_pixel + 5)) { //Collides with a medium invader + } else if (pixel_check >= first_medium_invader_pixel && pixel_check < first_small_invader_pixel) { //Collides with a medium invader + //Find the object no of the medium invader it hit, clears it and increments the score object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader); ClearSingleMediumInvader(object_no); score += 20; break; - } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_large_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_large_invader_pixel + 5)) { //Collides with a large invader + } else if (pixel_check >= first_large_invader_pixel && pixel_check < first_medium_invader_pixel) { //Collides with a large invader + //Find the object no of the large invader it hit, clears it and increments the score object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader); ClearSingleLargeInvader(object_no); score += 10; break; - } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_barrier_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_barrier_pixel + 3)) { //Collides with a barrier - CannonMissileHitBarrier(first_barrier_pixel, row); + } else if (pixel_check >= first_barrier_pixel && pixel_check < (first_barrier_pixel + 3)) { //Collides with a barrier + //Adds the destruction done to the barrier to the bitmap and redraws the barriers + CannonMissileHitBarrier(row); DrawBarriers(); break; - } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] == ufo_pixel) { //Collides with a UFO + } else if (pixel_check == ufo_pixel) { //Collides with a UFO pc.printf("UFO Hit\n"); cannon_missile_on_screen = false; move_cannon_missile.detach(); @@ -1296,45 +845,7 @@ } } -//Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer -void CollisionDetectionInvaderNormalMissile(int missile_no) -{ - //Invader missile coordinates shifted to match centre bottom of bitmap - int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1; - int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3; - if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) { - //Decrements the number of lives, pauses the game for 2 seconds - //Marks the cannon as hit - g_cannon_hit_flag = true; - //Detaches all tickers - DetachTickers(); - //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(); - } - AttachTickers(); - --number_of_lives; - invader_normal_missile[missile_no].fired = false; - move_invader_normal_missile[missile_no].detach(); - } else if (screen_buffer[relative_x_pos][relative_y_pos] >= first_barrier_pixel && screen_buffer[relative_x_pos][relative_y_pos] < (first_barrier_pixel + 3)) { - //Finds barrier number - InvaderNormalMissileHitBarrier(first_barrier_pixel, invader_normal_missile[missile_no]); - invader_normal_missile[missile_no].fired = false; - move_invader_normal_missile[missile_no].detach(); - } else { - for (int col = 0; col < 3; ++col) { - for (int row = 0; row < 4; ++row) { - if (invader_normal_missile_bitmap[row][col]) { - screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = invader_normal_missile_pixel; - } - } - } - } -} - -//Finds the invader number the shot hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen +//Finds the invader number the missile hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]) { int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel; @@ -1347,9 +858,9 @@ } //Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation -void CannonMissileHitBarrier(int first_pixel, int row) +void CannonMissileHitBarrier(int row) { - int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel; + int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_barrier_pixel; //Essentially inverse of barrier init int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1; int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; //Don't know why it's -1 and not -2 @@ -1357,6 +868,7 @@ for (int col = 0; col < 3; ++col) { for (int row_bit = 0; row_bit < 3; ++row_bit) { //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration + //Element by element multiplication of the 2 bitmaps to clear the required pixals if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) { barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_cannon_missile_damage_bitmap[row_bit][col]; } @@ -1366,24 +878,6 @@ move_cannon_missile.detach(); } -//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation -void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile)) -{ - int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_pixel; - //Essentially inverse of barrier init - int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1; - int relative_y_pos = (missile.y_pos + 3) - 33; - //Loops through the damage bitmap and modifies the barrier's after bitmap - for (int col = 0; col < 3; ++col) { - for (int row_bit = 0; row_bit < 2; ++row_bit) { - //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration - if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) { - barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col]; - } - } - } -} - void AttemptToFireInvaderNormalMissiles() { //Fires the normal missiles @@ -1419,7 +913,6 @@ } } -//Pass by reference to re void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader)) { //Finds the centre point of the chosen invader and fires the missile @@ -1432,10 +925,99 @@ move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05); } +void MoveInvaderNormalMissile(int missile_no) +{ + //Loops through the bitmap and clears the missile from the screen buffer + for (int col = 0; col < 3; ++col) { + for (int row = 0; row < 4; ++row) { + if (invader_normal_missile_bitmap[row][col]) { + screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel; + } + } + } + + //Checks missile will not exceed screen buffer + if (invader_normal_missile[missile_no].y_pos < 44) { + //Increments the position of the missile + ++invader_normal_missile[missile_no].y_pos; + + //Collision detection + CollisionDetectionInvaderNormalMissile(missile_no); + + } else { + //Sets the missiles fired flag as false and detaches the tickers + invader_normal_missile[missile_no].fired = false; + move_invader_normal_missile[missile_no].detach(); + } +} + +//Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer +void CollisionDetectionInvaderNormalMissile(int missile_no) +{ + //Invader missile coordinates shifted to match centre bottom of bitmap + int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1; + int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3; + if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) { + InvaderNormalMissileHitCannon(); + invader_normal_missile[missile_no].fired = false; + move_invader_normal_missile[missile_no].detach(); + } else if (screen_buffer[relative_x_pos][relative_y_pos] >= first_barrier_pixel && screen_buffer[relative_x_pos][relative_y_pos] < (first_barrier_pixel + 3)) { + //Finds barrier number + InvaderNormalMissileHitBarrier(invader_normal_missile[missile_no]); + invader_normal_missile[missile_no].fired = false; + move_invader_normal_missile[missile_no].detach(); + } else { + for (int col = 0; col < 3; ++col) { + for (int row = 0; row < 4; ++row) { + if (invader_normal_missile_bitmap[row][col]) { + screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = invader_normal_missile_pixel; + } + } + } + } +} + +void InvaderNormalMissileHitCannon() +{ + //Decrements the number of lives, pauses the game for 2 seconds + //Marks the cannon as hit + g_cannon_hit_flag = true; + //Detaches all tickers + DetachTickers(); + //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(); + } + AttachTickers(); + --number_of_lives; +} + +//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation +void InvaderNormalMissileHitBarrier(const struct InvaderNormalMissiles (&missile)) +{ + int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_barrier_pixel; + //Essentially inverse of barrier init + int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1; + int relative_y_pos = (missile.y_pos + 3) - 33; + //Loops through the damage bitmap and modifies the barrier's after bitmap + for (int col = 0; col < 3; ++col) { + for (int row_bit = 0; row_bit < 2; ++row_bit) { + //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration + if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) { + barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col]; + } + } + } +} + +//Detaches game related tickers void DetachTickers() { update_screen.detach(); move_enemies.detach(); + //Only detaches if missiles are on the screen if (cannon_missile_on_screen) { move_cannon_missile.detach(); } @@ -1446,11 +1028,12 @@ } } +//Attaches game related tickers void AttachTickers() { update_screen.attach(&update_screen_isr, 0.05); move_enemies.attach(&move_enemies_isr, ticker_period); - + //Only attaches if missiles were on the screen if (cannon_missile_on_screen) { move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); } @@ -1463,10 +1046,10 @@ void PauseScreen() { + //Prints the pause screen, score etc + PrintPauseScreen(); + 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