Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407
Dependencies: Joystick N5110 SDFileSystem mbed
main.cpp@11:eab3fb334bde, 2016-05-05 (annotated)
- Committer:
- avi23
- Date:
- Thu May 05 13:58:33 2016 +0000
- Revision:
- 11:eab3fb334bde
- Parent:
- 9:cbb982b7e353
Fixed Mute option leaving a trailing 'f'
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
avi23 | 8:b2faec20ed8f | 1 | /** |
avi23 | 8:b2faec20ed8f | 2 | @file main.cpp |
avi23 | 8:b2faec20ed8f | 3 | @brief Implementation File |
avi23 | 8:b2faec20ed8f | 4 | */ |
avi23 | 8:b2faec20ed8f | 5 | |
avi23 | 1:b300d052d549 | 6 | /* |
avi23 | 1:b300d052d549 | 7 | Space Invaders - Avinash Patel 200860407 |
avi23 | 1:b300d052d549 | 8 | |
avi23 | 1:b300d052d549 | 9 | Week 19 - Set up joystick class |
avi23 | 1:b300d052d549 | 10 | Week 20 - Changed to space invaders as constrained too much by screen resolution |
avi23 | 1:b300d052d549 | 11 | - Core cannon is drawn and can move, enemies are visible and they switch between states every second |
avi23 | 2:d34c95990605 | 12 | Week 21 - Begun to set up barriers |
avi23 | 5:34855f712350 | 13 | Easter - Barriers work, invader and player can shoot. Begun setting up menus |
avi23 | 7:babc367a3333 | 14 | Week 22 - Most menus work |
avi23 | 7:babc367a3333 | 15 | Week 23 - Menus work |
avi23 | 1:b300d052d549 | 16 | */ |
avi23 | 0:427469992efe | 17 | #include "mbed.h" |
avi23 | 7:babc367a3333 | 18 | #include "main.h" |
avi23 | 0:427469992efe | 19 | |
avi23 | 0:427469992efe | 20 | int main() |
avi23 | 0:427469992efe | 21 | { |
avi23 | 8:b2faec20ed8f | 22 | ///Wait for 2 seconds to allow power to settle |
avi23 | 5:34855f712350 | 23 | wait(1); |
avi23 | 8:b2faec20ed8f | 24 | ///Initalises the board and perhiperals |
avi23 | 0:427469992efe | 25 | init_K64F(); |
avi23 | 0:427469992efe | 26 | init_serial(); |
avi23 | 2:d34c95990605 | 27 | init_shoot(); |
avi23 | 5:34855f712350 | 28 | init_rng(); |
avi23 | 5:34855f712350 | 29 | joystick.init(); |
avi23 | 0:427469992efe | 30 | lcd.init(); |
avi23 | 0:427469992efe | 31 | lcd.clear(); |
avi23 | 0:427469992efe | 32 | |
avi23 | 9:cbb982b7e353 | 33 | LoadHighScores(); |
avi23 | 9:cbb982b7e353 | 34 | |
avi23 | 8:b2faec20ed8f | 35 | ///Configures the function pointer for the invaders normal missile |
avi23 | 5:34855f712350 | 36 | move_invader_normal_missile_isr[0] = &move_invader_normal_missile_0_isr; |
avi23 | 5:34855f712350 | 37 | move_invader_normal_missile_isr[1] = &move_invader_normal_missile_1_isr; |
avi23 | 0:427469992efe | 38 | |
avi23 | 8:b2faec20ed8f | 39 | ///Samples joystick every 0.05 second |
avi23 | 5:34855f712350 | 40 | move_joystick.attach(&move_joystick_isr, 0.05); |
avi23 | 2:d34c95990605 | 41 | |
avi23 | 9:cbb982b7e353 | 42 | ///Splash Screen |
avi23 | 9:cbb982b7e353 | 43 | SplashScreen(); |
avi23 | 9:cbb982b7e353 | 44 | |
avi23 | 2:d34c95990605 | 45 | while (true) { |
avi23 | 8:b2faec20ed8f | 46 | if (game_state == menu) { ///Menu screen |
avi23 | 8:b2faec20ed8f | 47 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 48 | fsm_state = 0; ///Sets the fsm state to 0 |
avi23 | 8:b2faec20ed8f | 49 | MenuScreen(); |
avi23 | 8:b2faec20ed8f | 50 | } else if (game_state == paused) { ///Paused screen |
avi23 | 8:b2faec20ed8f | 51 | ///Clears the screen |
avi23 | 2:d34c95990605 | 52 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 53 | fsm_state = 0; ///Ssets the fsm state to 0 |
avi23 | 8:b2faec20ed8f | 54 | PauseScreen(); |
avi23 | 8:b2faec20ed8f | 55 | } else if (game_state == game) { ///Game screen |
avi23 | 8:b2faec20ed8f | 56 | AttachTickers(); |
avi23 | 8:b2faec20ed8f | 57 | Game(); |
avi23 | 8:b2faec20ed8f | 58 | } else if (game_state == save) { |
avi23 | 9:cbb982b7e353 | 59 | SaveGameData(); |
avi23 | 8:b2faec20ed8f | 60 | } else if (game_state == load) { |
avi23 | 9:cbb982b7e353 | 61 | LoadGameData(); |
avi23 | 9:cbb982b7e353 | 62 | } else if (game_state == over) { |
avi23 | 9:cbb982b7e353 | 63 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 64 | GameOverScreen(); |
avi23 | 9:cbb982b7e353 | 65 | } else if (game_state == scores) { |
avi23 | 9:cbb982b7e353 | 66 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 67 | ScoreScreen(); |
avi23 | 9:cbb982b7e353 | 68 | } else if (game_state == settings) { |
avi23 | 9:cbb982b7e353 | 69 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 70 | fsm_state = 0; |
avi23 | 9:cbb982b7e353 | 71 | SettingsScreen(); |
avi23 | 0:427469992efe | 72 | } |
avi23 | 2:d34c95990605 | 73 | |
avi23 | 0:427469992efe | 74 | sleep(); |
avi23 | 0:427469992efe | 75 | } |
avi23 | 0:427469992efe | 76 | } |
avi23 | 0:427469992efe | 77 | |
avi23 | 0:427469992efe | 78 | void init_K64F() |
avi23 | 0:427469992efe | 79 | { |
avi23 | 8:b2faec20ed8f | 80 | /// on-board LEDs are active-low, so set pin high to turn them off. |
avi23 | 0:427469992efe | 81 | r_led = 1; |
avi23 | 0:427469992efe | 82 | g_led = 1; |
avi23 | 0:427469992efe | 83 | b_led = 1; |
avi23 | 0:427469992efe | 84 | |
avi23 | 8:b2faec20ed8f | 85 | /// since the on-board switches have external pull-ups, we should disable the internal pull-down |
avi23 | 8:b2faec20ed8f | 86 | /// resistors that are enabled by default using InterruptIn |
avi23 | 0:427469992efe | 87 | sw2.mode(PullNone); |
avi23 | 0:427469992efe | 88 | sw3.mode(PullNone); |
avi23 | 0:427469992efe | 89 | } |
avi23 | 0:427469992efe | 90 | |
avi23 | 0:427469992efe | 91 | void error() |
avi23 | 0:427469992efe | 92 | { |
avi23 | 8:b2faec20ed8f | 93 | while(1) { /// if error, hang while flashing error message |
avi23 | 0:427469992efe | 94 | r_led = 0; |
avi23 | 0:427469992efe | 95 | wait(0.2); |
avi23 | 0:427469992efe | 96 | r_led = 1; |
avi23 | 0:427469992efe | 97 | wait(0.2); |
avi23 | 0:427469992efe | 98 | } |
avi23 | 0:427469992efe | 99 | } |
avi23 | 0:427469992efe | 100 | |
avi23 | 0:427469992efe | 101 | void init_serial() |
avi23 | 0:427469992efe | 102 | { |
avi23 | 8:b2faec20ed8f | 103 | /// set to highest baud - ensure terminal software matches |
avi23 | 0:427469992efe | 104 | pc.baud(115200); |
avi23 | 0:427469992efe | 105 | } |
avi23 | 0:427469992efe | 106 | |
avi23 | 8:b2faec20ed8f | 107 | ///Seeds the random number generator with noise from an analog in pin |
avi23 | 5:34855f712350 | 108 | void init_rng() |
avi23 | 5:34855f712350 | 109 | { |
avi23 | 8:b2faec20ed8f | 110 | AnalogIn rng_seed(PTC10); ///Creates a AnalogIn on a unused pin |
avi23 | 8:b2faec20ed8f | 111 | srand(floor(10000*rng_seed.read())); ///Sets the seed as 10000x the input of the analog in |
avi23 | 5:34855f712350 | 112 | } |
avi23 | 5:34855f712350 | 113 | |
avi23 | 2:d34c95990605 | 114 | void init_shoot() |
avi23 | 0:427469992efe | 115 | { |
avi23 | 2:d34c95990605 | 116 | shoot_button.mode(PullUp); |
avi23 | 2:d34c95990605 | 117 | shoot_button.fall(&shoot_pressed_isr); |
avi23 | 9:cbb982b7e353 | 118 | shoot_button.rise(&shoot_pressed_rise_isr); |
avi23 | 2:d34c95990605 | 119 | } |
avi23 | 2:d34c95990605 | 120 | |
avi23 | 2:d34c95990605 | 121 | void update_screen_isr() |
avi23 | 2:d34c95990605 | 122 | { |
avi23 | 2:d34c95990605 | 123 | g_update_screen_flag = true; |
avi23 | 0:427469992efe | 124 | } |
avi23 | 0:427469992efe | 125 | |
avi23 | 5:34855f712350 | 126 | void move_enemies_isr() |
avi23 | 5:34855f712350 | 127 | { |
avi23 | 5:34855f712350 | 128 | g_move_enemies_flag = true; |
avi23 | 5:34855f712350 | 129 | } |
avi23 | 5:34855f712350 | 130 | |
avi23 | 2:d34c95990605 | 131 | void shoot_pressed_isr() |
avi23 | 2:d34c95990605 | 132 | { |
avi23 | 8:b2faec20ed8f | 133 | ///Only sets the shoot pressed flag 0.1s after the last press |
avi23 | 6:89d4a7f7588b | 134 | if (!g_shoot_button_debounce_flag) { |
avi23 | 6:89d4a7f7588b | 135 | g_shoot_pressed_flag = true; |
avi23 | 6:89d4a7f7588b | 136 | g_shoot_button_debounce_flag = true; |
avi23 | 6:89d4a7f7588b | 137 | } |
avi23 | 5:34855f712350 | 138 | } |
avi23 | 5:34855f712350 | 139 | |
avi23 | 5:34855f712350 | 140 | void move_cannon_missile_isr() |
avi23 | 5:34855f712350 | 141 | { |
avi23 | 5:34855f712350 | 142 | g_move_cannon_missile_flag = true; |
avi23 | 5:34855f712350 | 143 | } |
avi23 | 5:34855f712350 | 144 | |
avi23 | 5:34855f712350 | 145 | void move_joystick_isr() |
avi23 | 5:34855f712350 | 146 | { |
avi23 | 8:b2faec20ed8f | 147 | ///Always set the move flag in a game |
avi23 | 5:34855f712350 | 148 | if (game_state == game) { |
avi23 | 5:34855f712350 | 149 | g_move_joystick_flag = true; |
avi23 | 5:34855f712350 | 150 | } else if (!g_joystick_cursor_regulator_flag) { |
avi23 | 8:b2faec20ed8f | 151 | ///Only sets the flag if the regulator is not set |
avi23 | 5:34855f712350 | 152 | g_move_joystick_flag = true; |
avi23 | 5:34855f712350 | 153 | g_joystick_cursor_regulator_flag = true; |
avi23 | 5:34855f712350 | 154 | |
avi23 | 8:b2faec20ed8f | 155 | ///Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically |
avi23 | 6:89d4a7f7588b | 156 | joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.1); |
avi23 | 5:34855f712350 | 157 | } |
avi23 | 5:34855f712350 | 158 | } |
avi23 | 5:34855f712350 | 159 | |
avi23 | 6:89d4a7f7588b | 160 | void joystick_cursor_regulator_isr() |
avi23 | 6:89d4a7f7588b | 161 | { |
avi23 | 5:34855f712350 | 162 | g_joystick_cursor_regulator_flag = false; |
avi23 | 5:34855f712350 | 163 | } |
avi23 | 5:34855f712350 | 164 | |
avi23 | 6:89d4a7f7588b | 165 | void shoot_button_debounce_isr() |
avi23 | 6:89d4a7f7588b | 166 | { |
avi23 | 6:89d4a7f7588b | 167 | g_shoot_button_debounce_flag = false; |
avi23 | 6:89d4a7f7588b | 168 | } |
avi23 | 6:89d4a7f7588b | 169 | |
avi23 | 5:34855f712350 | 170 | void move_invader_normal_missile_0_isr() |
avi23 | 5:34855f712350 | 171 | { |
avi23 | 5:34855f712350 | 172 | g_move_invader_normal_missile_flag[0] = true; |
avi23 | 5:34855f712350 | 173 | } |
avi23 | 5:34855f712350 | 174 | |
avi23 | 5:34855f712350 | 175 | void move_invader_normal_missile_1_isr() |
avi23 | 5:34855f712350 | 176 | { |
avi23 | 5:34855f712350 | 177 | g_move_invader_normal_missile_flag[1] = true; |
avi23 | 5:34855f712350 | 178 | } |
avi23 | 5:34855f712350 | 179 | |
avi23 | 5:34855f712350 | 180 | void cannon_hit_isr() |
avi23 | 5:34855f712350 | 181 | { |
avi23 | 5:34855f712350 | 182 | g_cannon_hit_flag = false; |
avi23 | 2:d34c95990605 | 183 | } |
avi23 | 2:d34c95990605 | 184 | |
avi23 | 8:b2faec20ed8f | 185 | void move_ufo_isr() |
avi23 | 8:b2faec20ed8f | 186 | { |
avi23 | 8:b2faec20ed8f | 187 | g_move_ufo_flag = true; |
avi23 | 8:b2faec20ed8f | 188 | } |
avi23 | 8:b2faec20ed8f | 189 | |
avi23 | 8:b2faec20ed8f | 190 | void fire_buzzer_isr() |
avi23 | 8:b2faec20ed8f | 191 | { |
avi23 | 8:b2faec20ed8f | 192 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 193 | } |
avi23 | 8:b2faec20ed8f | 194 | |
avi23 | 9:cbb982b7e353 | 195 | void lp_wait_isr() |
avi23 | 9:cbb982b7e353 | 196 | { |
avi23 | 9:cbb982b7e353 | 197 | g_lp_wait_flag = false; |
avi23 | 9:cbb982b7e353 | 198 | } |
avi23 | 9:cbb982b7e353 | 199 | |
avi23 | 9:cbb982b7e353 | 200 | void shoot_pressed_rise_isr() |
avi23 | 9:cbb982b7e353 | 201 | { |
avi23 | 9:cbb982b7e353 | 202 | ///Attaches a timeout to clear the debounce flag in 0.125 seconds |
avi23 | 9:cbb982b7e353 | 203 | shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125); |
avi23 | 9:cbb982b7e353 | 204 | } |
avi23 | 9:cbb982b7e353 | 205 | |
avi23 | 5:34855f712350 | 206 | void Game() |
avi23 | 6:89d4a7f7588b | 207 | { |
avi23 | 8:b2faec20ed8f | 208 | ///Stays within the loop while the selected state is game |
avi23 | 5:34855f712350 | 209 | while (game_state == game) { |
avi23 | 8:b2faec20ed8f | 210 | pc.printf("Mute: %d\n", is_muted); |
avi23 | 9:cbb982b7e353 | 211 | ///If the game is over detach all the tickers and set game state to over |
avi23 | 5:34855f712350 | 212 | if (number_of_lives == 0) { |
avi23 | 5:34855f712350 | 213 | DetachTickers(); |
avi23 | 9:cbb982b7e353 | 214 | game_state = over; |
avi23 | 8:b2faec20ed8f | 215 | } else if (no_of_alive_invaders == 0) { ///If the player wins a round |
avi23 | 8:b2faec20ed8f | 216 | ///Resets the no of alive invaders |
avi23 | 5:34855f712350 | 217 | no_of_alive_invaders = 15; |
avi23 | 8:b2faec20ed8f | 218 | down_count = 0; |
avi23 | 8:b2faec20ed8f | 219 | ///Detaches the enemy ticker while reinitalising invaders |
avi23 | 5:34855f712350 | 220 | move_enemies.detach(); |
avi23 | 8:b2faec20ed8f | 221 | ///Reinitalises objects |
avi23 | 5:34855f712350 | 222 | InitSmallInvaders(); |
avi23 | 5:34855f712350 | 223 | InitMediumInvaders(); |
avi23 | 5:34855f712350 | 224 | InitLargeInvaders(); |
avi23 | 8:b2faec20ed8f | 225 | ///Reattaches enemy ticker |
avi23 | 5:34855f712350 | 226 | move_enemies.attach(&move_enemies_isr, 1); |
avi23 | 5:34855f712350 | 227 | } else { |
avi23 | 8:b2faec20ed8f | 228 | ///Updates pixels on the screen |
avi23 | 5:34855f712350 | 229 | if (g_update_screen_flag) { |
avi23 | 5:34855f712350 | 230 | g_update_screen_flag = false; |
avi23 | 5:34855f712350 | 231 | |
avi23 | 5:34855f712350 | 232 | UpdateScreen(); |
avi23 | 5:34855f712350 | 233 | } |
avi23 | 5:34855f712350 | 234 | |
avi23 | 8:b2faec20ed8f | 235 | ///Controls cannon movement |
avi23 | 5:34855f712350 | 236 | if (g_move_joystick_flag) { |
avi23 | 5:34855f712350 | 237 | g_move_joystick_flag = false; |
avi23 | 5:34855f712350 | 238 | |
avi23 | 5:34855f712350 | 239 | MoveCannon(); |
avi23 | 5:34855f712350 | 240 | DrawBarriers(); |
avi23 | 5:34855f712350 | 241 | } |
avi23 | 5:34855f712350 | 242 | |
avi23 | 8:b2faec20ed8f | 243 | ///Controls enemy movement |
avi23 | 5:34855f712350 | 244 | if (g_move_enemies_flag) { |
avi23 | 5:34855f712350 | 245 | g_move_enemies_flag = false; |
avi23 | 5:34855f712350 | 246 | |
avi23 | 8:b2faec20ed8f | 247 | ///Increses the speed the invaders move |
avi23 | 5:34855f712350 | 248 | move_enemies.detach(); |
avi23 | 5:34855f712350 | 249 | ticker_period = 0.1+(no_of_alive_invaders*0.06); |
avi23 | 5:34855f712350 | 250 | move_enemies.attach(&move_enemies_isr, ticker_period); |
avi23 | 5:34855f712350 | 251 | |
avi23 | 8:b2faec20ed8f | 252 | //Attach the buzzer timeout if mute is unselected |
avi23 | 8:b2faec20ed8f | 253 | if (!is_muted) { |
avi23 | 8:b2faec20ed8f | 254 | fire_buzzer.attach(&fire_buzzer_isr, ticker_period/2.0f); |
avi23 | 8:b2faec20ed8f | 255 | } |
avi23 | 8:b2faec20ed8f | 256 | |
avi23 | 8:b2faec20ed8f | 257 | ///Clears the old bitmaps |
avi23 | 5:34855f712350 | 258 | ClearSmallInvaders(); |
avi23 | 5:34855f712350 | 259 | ClearMediumInvaders(); |
avi23 | 5:34855f712350 | 260 | ClearLargeInvaders(); |
avi23 | 5:34855f712350 | 261 | |
avi23 | 5:34855f712350 | 262 | MoveInvaderXPositions(); |
avi23 | 8:b2faec20ed8f | 263 | ///Switches the bitmap state |
avi23 | 5:34855f712350 | 264 | invaders_in_state2 = !invaders_in_state2; |
avi23 | 5:34855f712350 | 265 | |
avi23 | 8:b2faec20ed8f | 266 | ///Draws the invaders |
avi23 | 5:34855f712350 | 267 | DrawSmallInvaders(); |
avi23 | 5:34855f712350 | 268 | DrawMediumInvaders(); |
avi23 | 5:34855f712350 | 269 | DrawLargeInvaders(); |
avi23 | 5:34855f712350 | 270 | |
avi23 | 8:b2faec20ed8f | 271 | ///Attempts to fire the invaders missiles |
avi23 | 5:34855f712350 | 272 | AttemptToFireInvaderNormalMissiles(); |
avi23 | 8:b2faec20ed8f | 273 | |
avi23 | 8:b2faec20ed8f | 274 | ///Attempts to spawn UFO |
avi23 | 8:b2faec20ed8f | 275 | AttemptToSpawnUFO(); |
avi23 | 5:34855f712350 | 276 | } |
avi23 | 5:34855f712350 | 277 | |
avi23 | 8:b2faec20ed8f | 278 | if (g_fire_buzzer_flag && !is_muted) { |
avi23 | 8:b2faec20ed8f | 279 | g_fire_buzzer_flag = false; |
avi23 | 8:b2faec20ed8f | 280 | |
avi23 | 9:cbb982b7e353 | 281 | PlayBuzzer(); |
avi23 | 8:b2faec20ed8f | 282 | } |
avi23 | 8:b2faec20ed8f | 283 | |
avi23 | 8:b2faec20ed8f | 284 | ///Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen |
avi23 | 5:34855f712350 | 285 | if (g_shoot_pressed_flag) { |
avi23 | 5:34855f712350 | 286 | g_shoot_pressed_flag = false; |
avi23 | 5:34855f712350 | 287 | |
avi23 | 5:34855f712350 | 288 | if (!cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 289 | FireCannonMissile(); |
avi23 | 8:b2faec20ed8f | 290 | |
avi23 | 8:b2faec20ed8f | 291 | ///Counts fired missiles to see if the ufo bonus can be applied |
avi23 | 8:b2faec20ed8f | 292 | if (ufo_bonus && shot_count > 14) { |
avi23 | 8:b2faec20ed8f | 293 | shot_count = 0; |
avi23 | 8:b2faec20ed8f | 294 | } else if (shot_count > 22) { |
avi23 | 8:b2faec20ed8f | 295 | shot_count = 0; |
avi23 | 8:b2faec20ed8f | 296 | } else { |
avi23 | 8:b2faec20ed8f | 297 | ++shot_count; |
avi23 | 8:b2faec20ed8f | 298 | } |
avi23 | 5:34855f712350 | 299 | } |
avi23 | 5:34855f712350 | 300 | } |
avi23 | 5:34855f712350 | 301 | |
avi23 | 8:b2faec20ed8f | 302 | ///Move the cannon shot |
avi23 | 5:34855f712350 | 303 | if (g_move_cannon_missile_flag) { |
avi23 | 5:34855f712350 | 304 | g_move_cannon_missile_flag = false; |
avi23 | 5:34855f712350 | 305 | |
avi23 | 5:34855f712350 | 306 | MoveCannonMissile(); |
avi23 | 5:34855f712350 | 307 | } |
avi23 | 5:34855f712350 | 308 | |
avi23 | 8:b2faec20ed8f | 309 | ///Moves the invaders 1st normal missile |
avi23 | 5:34855f712350 | 310 | if (g_move_invader_normal_missile_flag[0]) { |
avi23 | 5:34855f712350 | 311 | g_move_invader_normal_missile_flag[0] = false; |
avi23 | 5:34855f712350 | 312 | |
avi23 | 5:34855f712350 | 313 | MoveInvaderNormalMissile(0); |
avi23 | 5:34855f712350 | 314 | } |
avi23 | 5:34855f712350 | 315 | |
avi23 | 8:b2faec20ed8f | 316 | ///Moves the invaders 2nd normal missile |
avi23 | 5:34855f712350 | 317 | if (g_move_invader_normal_missile_flag[1]) { |
avi23 | 5:34855f712350 | 318 | g_move_invader_normal_missile_flag[1] = false; |
avi23 | 5:34855f712350 | 319 | |
avi23 | 5:34855f712350 | 320 | MoveInvaderNormalMissile(1); |
avi23 | 5:34855f712350 | 321 | } |
avi23 | 5:34855f712350 | 322 | |
avi23 | 8:b2faec20ed8f | 323 | ///Moves the UFO |
avi23 | 8:b2faec20ed8f | 324 | if (g_move_ufo_flag) { |
avi23 | 8:b2faec20ed8f | 325 | g_move_ufo_flag = false; |
avi23 | 8:b2faec20ed8f | 326 | |
avi23 | 8:b2faec20ed8f | 327 | ///Clears the UFO |
avi23 | 8:b2faec20ed8f | 328 | ClearUFO(); |
avi23 | 8:b2faec20ed8f | 329 | |
avi23 | 8:b2faec20ed8f | 330 | ///Moves the UFO in the correct direction |
avi23 | 8:b2faec20ed8f | 331 | if (ufo_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 332 | ufo_x_pos += 2; |
avi23 | 8:b2faec20ed8f | 333 | } else { |
avi23 | 8:b2faec20ed8f | 334 | ufo_x_pos -= 2; |
avi23 | 8:b2faec20ed8f | 335 | } |
avi23 | 8:b2faec20ed8f | 336 | |
avi23 | 8:b2faec20ed8f | 337 | ///Draws the UFO |
avi23 | 8:b2faec20ed8f | 338 | DrawUFO(); |
avi23 | 8:b2faec20ed8f | 339 | } |
avi23 | 8:b2faec20ed8f | 340 | |
avi23 | 5:34855f712350 | 341 | if (joystick.get_button_flag()) { |
avi23 | 5:34855f712350 | 342 | joystick.set_button_flag(0); |
avi23 | 5:34855f712350 | 343 | |
avi23 | 9:cbb982b7e353 | 344 | ///Detach all game tickers and turn off PWM |
avi23 | 5:34855f712350 | 345 | DetachTickers(); |
avi23 | 9:cbb982b7e353 | 346 | buzzer.write(0.0); |
avi23 | 5:34855f712350 | 347 | game_state = paused; |
avi23 | 5:34855f712350 | 348 | } |
avi23 | 5:34855f712350 | 349 | } |
avi23 | 5:34855f712350 | 350 | |
avi23 | 5:34855f712350 | 351 | sleep(); |
avi23 | 5:34855f712350 | 352 | } |
avi23 | 2:d34c95990605 | 353 | } |
avi23 | 2:d34c95990605 | 354 | |
avi23 | 7:babc367a3333 | 355 | void InitaliseGame() |
avi23 | 7:babc367a3333 | 356 | { |
avi23 | 8:b2faec20ed8f | 357 | ///Clears the screen buffer and runs init functions |
avi23 | 7:babc367a3333 | 358 | memset(screen_buffer, 0, sizeof(screen_buffer)); |
avi23 | 7:babc367a3333 | 359 | no_of_alive_invaders = 15; |
avi23 | 7:babc367a3333 | 360 | score = 0; |
avi23 | 7:babc367a3333 | 361 | number_of_lives = 3; |
avi23 | 8:b2faec20ed8f | 362 | down_count = 0; |
avi23 | 9:cbb982b7e353 | 363 | cannon_xpos = 13; |
avi23 | 9:cbb982b7e353 | 364 | ufo_on_screen = false; |
avi23 | 8:b2faec20ed8f | 365 | ufo_bonus = false; |
avi23 | 8:b2faec20ed8f | 366 | shot_count = 0; |
avi23 | 7:babc367a3333 | 367 | InitSmallInvaders(); |
avi23 | 7:babc367a3333 | 368 | InitMediumInvaders(); |
avi23 | 7:babc367a3333 | 369 | InitLargeInvaders(); |
avi23 | 7:babc367a3333 | 370 | InitBarriers(); |
avi23 | 8:b2faec20ed8f | 371 | ///If the sound is set activate the buzzer flag |
avi23 | 8:b2faec20ed8f | 372 | if (!is_muted) { |
avi23 | 8:b2faec20ed8f | 373 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 374 | } |
avi23 | 8:b2faec20ed8f | 375 | ///Sets the flags so enemies pop up straight away |
avi23 | 7:babc367a3333 | 376 | g_update_screen_flag = true; |
avi23 | 7:babc367a3333 | 377 | g_move_joystick_flag = true; |
avi23 | 7:babc367a3333 | 378 | g_move_enemies_flag = true; |
avi23 | 8:b2faec20ed8f | 379 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 380 | ///Forces the missiles to have the fired flags to flase |
avi23 | 7:babc367a3333 | 381 | cannon_missile_on_screen = false; |
avi23 | 7:babc367a3333 | 382 | invader_normal_missile[0].fired = false; |
avi23 | 7:babc367a3333 | 383 | invader_normal_missile[1].fired = false; |
avi23 | 7:babc367a3333 | 384 | } |
avi23 | 7:babc367a3333 | 385 | |
avi23 | 5:34855f712350 | 386 | void UpdateScreen() |
avi23 | 2:d34c95990605 | 387 | { |
avi23 | 8:b2faec20ed8f | 388 | ///Loops through the screen buffer and sets pixels on the LCD |
avi23 | 5:34855f712350 | 389 | for (int col = 0; col < 84; ++col) { |
avi23 | 5:34855f712350 | 390 | for (int row = 0; row < 48; ++row) { |
avi23 | 5:34855f712350 | 391 | if (screen_buffer[col][row]) { |
avi23 | 5:34855f712350 | 392 | lcd.setPixel(col, row); |
avi23 | 5:34855f712350 | 393 | } else { |
avi23 | 5:34855f712350 | 394 | lcd.clearPixel(col, row); |
avi23 | 5:34855f712350 | 395 | } |
avi23 | 5:34855f712350 | 396 | } |
avi23 | 5:34855f712350 | 397 | } |
avi23 | 5:34855f712350 | 398 | |
avi23 | 5:34855f712350 | 399 | lcd.refresh(); |
avi23 | 2:d34c95990605 | 400 | } |
avi23 | 2:d34c95990605 | 401 | |
avi23 | 2:d34c95990605 | 402 | void MoveCannon() |
avi23 | 0:427469992efe | 403 | { |
avi23 | 8:b2faec20ed8f | 404 | ///Clears the cannon |
avi23 | 5:34855f712350 | 405 | for (int col = 0; col < 9; ++col) { |
avi23 | 5:34855f712350 | 406 | for (int row = 0; row < 5; ++row) { |
avi23 | 1:b300d052d549 | 407 | if(cannon_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 408 | screen_buffer[cannon_xpos+col][cannon_ypos+row] = empty_pixel; |
avi23 | 0:427469992efe | 409 | } |
avi23 | 0:427469992efe | 410 | } |
avi23 | 0:427469992efe | 411 | } |
avi23 | 0:427469992efe | 412 | |
avi23 | 8:b2faec20ed8f | 413 | ///Changes the position of the cannon when the joystick is moved, capping at 0 and 75 so it always fits on the screen |
avi23 | 0:427469992efe | 414 | if (joystick.GetXValue() < 0.25f) { |
avi23 | 1:b300d052d549 | 415 | cannon_xpos--; |
avi23 | 1:b300d052d549 | 416 | if (cannon_xpos < 0) { |
avi23 | 1:b300d052d549 | 417 | cannon_xpos = 0; |
avi23 | 0:427469992efe | 418 | } |
avi23 | 0:427469992efe | 419 | } else if (joystick.GetXValue() > 0.75f) { |
avi23 | 1:b300d052d549 | 420 | cannon_xpos++; |
avi23 | 1:b300d052d549 | 421 | if (cannon_xpos > 75) { |
avi23 | 1:b300d052d549 | 422 | cannon_xpos = 75; |
avi23 | 0:427469992efe | 423 | } |
avi23 | 0:427469992efe | 424 | } |
avi23 | 0:427469992efe | 425 | |
avi23 | 8:b2faec20ed8f | 426 | ///Redraws the cannon |
avi23 | 5:34855f712350 | 427 | for (int col = 0; col < 9; ++col) { |
avi23 | 5:34855f712350 | 428 | for (int row = 0; row < 5; ++row) { |
avi23 | 1:b300d052d549 | 429 | if(cannon_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 430 | screen_buffer[cannon_xpos+col][cannon_ypos+row] = cannon_pixel; |
avi23 | 0:427469992efe | 431 | } |
avi23 | 0:427469992efe | 432 | } |
avi23 | 0:427469992efe | 433 | } |
avi23 | 0:427469992efe | 434 | } |
avi23 | 0:427469992efe | 435 | |
avi23 | 8:b2faec20ed8f | 436 | ///Sets the position and status of the small invaders |
avi23 | 0:427469992efe | 437 | void InitSmallInvaders() |
avi23 | 0:427469992efe | 438 | { |
avi23 | 5:34855f712350 | 439 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 440 | small_invader[i].x_pos = 2 + (i*13); /// Large invaders are 12 across so add 13 for a gap space |
avi23 | 2:d34c95990605 | 441 | small_invader[i].y_pos = 1; |
avi23 | 5:34855f712350 | 442 | small_invader[i].status = alive; |
avi23 | 0:427469992efe | 443 | } |
avi23 | 0:427469992efe | 444 | } |
avi23 | 0:427469992efe | 445 | |
avi23 | 8:b2faec20ed8f | 446 | ///Cycles through all the small invaders. If they're not already dead clear them |
avi23 | 2:d34c95990605 | 447 | void ClearSmallInvaders() |
avi23 | 2:d34c95990605 | 448 | { |
avi23 | 5:34855f712350 | 449 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 450 | if (small_invader[i].status) { |
avi23 | 5:34855f712350 | 451 | ClearSingleSmallInvader(i); |
avi23 | 5:34855f712350 | 452 | } |
avi23 | 5:34855f712350 | 453 | } |
avi23 | 5:34855f712350 | 454 | } |
avi23 | 5:34855f712350 | 455 | |
avi23 | 8:b2faec20ed8f | 456 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0 |
avi23 | 5:34855f712350 | 457 | void ClearSingleSmallInvader(int invader_no) |
avi23 | 5:34855f712350 | 458 | { |
avi23 | 5:34855f712350 | 459 | for (int col = 0; col < 8; ++col) { |
avi23 | 5:34855f712350 | 460 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 461 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 462 | if (small_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 463 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 464 | } |
avi23 | 5:34855f712350 | 465 | } else { |
avi23 | 5:34855f712350 | 466 | if (small_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 467 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 468 | } |
avi23 | 2:d34c95990605 | 469 | } |
avi23 | 2:d34c95990605 | 470 | } |
avi23 | 2:d34c95990605 | 471 | } |
avi23 | 5:34855f712350 | 472 | |
avi23 | 5:34855f712350 | 473 | small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 2:d34c95990605 | 474 | } |
avi23 | 2:d34c95990605 | 475 | |
avi23 | 8:b2faec20ed8f | 476 | ///Cycles through all the small invaders. If they're alive set them in the screen buffer |
avi23 | 0:427469992efe | 477 | void DrawSmallInvaders() |
avi23 | 0:427469992efe | 478 | { |
avi23 | 5:34855f712350 | 479 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 480 | if (small_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 481 | DrawSingleSmallInvader(i); |
avi23 | 5:34855f712350 | 482 | } |
avi23 | 5:34855f712350 | 483 | } |
avi23 | 5:34855f712350 | 484 | } |
avi23 | 5:34855f712350 | 485 | |
avi23 | 8:b2faec20ed8f | 486 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 487 | void DrawSingleSmallInvader(int invader_no) |
avi23 | 5:34855f712350 | 488 | { |
avi23 | 5:34855f712350 | 489 | for (int col = 0; col < 8; ++col) { |
avi23 | 5:34855f712350 | 490 | for (int row = 0; row < 6; ++row) { |
avi23 | 2:d34c95990605 | 491 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 492 | if (small_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 493 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = first_small_invader_pixel + invader_no; |
avi23 | 0:427469992efe | 494 | } |
avi23 | 0:427469992efe | 495 | } else { |
avi23 | 5:34855f712350 | 496 | if (small_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 497 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = first_small_invader_pixel + invader_no; |
avi23 | 0:427469992efe | 498 | } |
avi23 | 0:427469992efe | 499 | } |
avi23 | 0:427469992efe | 500 | } |
avi23 | 0:427469992efe | 501 | } |
avi23 | 1:b300d052d549 | 502 | } |
avi23 | 1:b300d052d549 | 503 | |
avi23 | 8:b2faec20ed8f | 504 | ///Sets the position and aliveness of the medium invaders |
avi23 | 1:b300d052d549 | 505 | void InitMediumInvaders() |
avi23 | 1:b300d052d549 | 506 | { |
avi23 | 5:34855f712350 | 507 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 508 | medium_invader[i].x_pos = 1 + (i*13); /// Large invaders are 12 across so add 13 for a gap space |
avi23 | 2:d34c95990605 | 509 | medium_invader[i].y_pos = 8; |
avi23 | 5:34855f712350 | 510 | medium_invader[i].status = alive; |
avi23 | 1:b300d052d549 | 511 | } |
avi23 | 1:b300d052d549 | 512 | } |
avi23 | 1:b300d052d549 | 513 | |
avi23 | 8:b2faec20ed8f | 514 | ///Cycles through all the medium invaders. If they're not already dead clear them |
avi23 | 2:d34c95990605 | 515 | void ClearMediumInvaders() |
avi23 | 2:d34c95990605 | 516 | { |
avi23 | 5:34855f712350 | 517 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 518 | if (medium_invader[i].status) { |
avi23 | 5:34855f712350 | 519 | ClearSingleMediumInvader(i); |
avi23 | 2:d34c95990605 | 520 | } |
avi23 | 2:d34c95990605 | 521 | } |
avi23 | 2:d34c95990605 | 522 | } |
avi23 | 2:d34c95990605 | 523 | |
avi23 | 8:b2faec20ed8f | 524 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0 |
avi23 | 5:34855f712350 | 525 | void ClearSingleMediumInvader(int invader_no) |
avi23 | 5:34855f712350 | 526 | { |
avi23 | 5:34855f712350 | 527 | for (int col = 0; col < 10; ++col) { |
avi23 | 5:34855f712350 | 528 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 529 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 530 | if (medium_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 531 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 532 | } |
avi23 | 5:34855f712350 | 533 | } else { |
avi23 | 5:34855f712350 | 534 | if (medium_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 535 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 536 | } |
avi23 | 5:34855f712350 | 537 | } |
avi23 | 5:34855f712350 | 538 | } |
avi23 | 5:34855f712350 | 539 | } |
avi23 | 5:34855f712350 | 540 | |
avi23 | 5:34855f712350 | 541 | medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 5:34855f712350 | 542 | } |
avi23 | 5:34855f712350 | 543 | |
avi23 | 8:b2faec20ed8f | 544 | ///Cycles through all the medium invaders. If they're alive set them in the screen buffer |
avi23 | 1:b300d052d549 | 545 | void DrawMediumInvaders() |
avi23 | 1:b300d052d549 | 546 | { |
avi23 | 5:34855f712350 | 547 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 548 | if (medium_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 549 | DrawSingleMediumInvader(i); |
avi23 | 5:34855f712350 | 550 | } |
avi23 | 5:34855f712350 | 551 | } |
avi23 | 5:34855f712350 | 552 | } |
avi23 | 5:34855f712350 | 553 | |
avi23 | 8:b2faec20ed8f | 554 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 555 | void DrawSingleMediumInvader(int invader_no) |
avi23 | 5:34855f712350 | 556 | { |
avi23 | 5:34855f712350 | 557 | for (int col = 0; col < 10; ++col) { |
avi23 | 5:34855f712350 | 558 | for (int row = 0; row < 6; ++row) { |
avi23 | 2:d34c95990605 | 559 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 560 | if (medium_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 561 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = first_medium_invader_pixel + invader_no; |
avi23 | 1:b300d052d549 | 562 | } |
avi23 | 1:b300d052d549 | 563 | } else { |
avi23 | 5:34855f712350 | 564 | if (medium_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 565 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = first_medium_invader_pixel + invader_no; |
avi23 | 1:b300d052d549 | 566 | } |
avi23 | 1:b300d052d549 | 567 | } |
avi23 | 1:b300d052d549 | 568 | } |
avi23 | 1:b300d052d549 | 569 | } |
avi23 | 1:b300d052d549 | 570 | } |
avi23 | 1:b300d052d549 | 571 | |
avi23 | 8:b2faec20ed8f | 572 | ///Sets the position and status of the large invaders |
avi23 | 1:b300d052d549 | 573 | void InitLargeInvaders() |
avi23 | 1:b300d052d549 | 574 | { |
avi23 | 5:34855f712350 | 575 | for (int i = 0; i < 5; ++i) { |
avi23 | 1:b300d052d549 | 576 | large_invader[i].x_pos = 0 + (i*13); |
avi23 | 2:d34c95990605 | 577 | large_invader[i].y_pos = 15; |
avi23 | 5:34855f712350 | 578 | large_invader[i].status = alive; |
avi23 | 5:34855f712350 | 579 | } |
avi23 | 5:34855f712350 | 580 | } |
avi23 | 5:34855f712350 | 581 | |
avi23 | 8:b2faec20ed8f | 582 | ///Cycles through all the large invaders. If they're not already dead clear them |
avi23 | 5:34855f712350 | 583 | void ClearLargeInvaders() |
avi23 | 5:34855f712350 | 584 | { |
avi23 | 5:34855f712350 | 585 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 586 | if (large_invader[i].status) { |
avi23 | 5:34855f712350 | 587 | ClearSingleLargeInvader(i); |
avi23 | 5:34855f712350 | 588 | } |
avi23 | 1:b300d052d549 | 589 | } |
avi23 | 1:b300d052d549 | 590 | } |
avi23 | 1:b300d052d549 | 591 | |
avi23 | 8:b2faec20ed8f | 592 | ///Loops through the large invader bitmap, if the pixel in the bitmap is set to 1, set the pixel in the buffer to 0 |
avi23 | 5:34855f712350 | 593 | void ClearSingleLargeInvader(int invader_no) |
avi23 | 2:d34c95990605 | 594 | { |
avi23 | 5:34855f712350 | 595 | for (int col = 0; col < 12; ++col) { |
avi23 | 5:34855f712350 | 596 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 597 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 598 | if (large_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 599 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 600 | } |
avi23 | 5:34855f712350 | 601 | } else { |
avi23 | 5:34855f712350 | 602 | if (large_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 603 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 604 | } |
avi23 | 2:d34c95990605 | 605 | } |
avi23 | 5:34855f712350 | 606 | } |
avi23 | 5:34855f712350 | 607 | } |
avi23 | 5:34855f712350 | 608 | |
avi23 | 5:34855f712350 | 609 | large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 5:34855f712350 | 610 | } |
avi23 | 5:34855f712350 | 611 | |
avi23 | 8:b2faec20ed8f | 612 | ///Cycles through all the large invaders. If they're alive set them in the screen buffer |
avi23 | 5:34855f712350 | 613 | void DrawLargeInvaders() |
avi23 | 5:34855f712350 | 614 | { |
avi23 | 5:34855f712350 | 615 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 616 | if (large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 617 | DrawSingleLargeInvader(i); |
avi23 | 5:34855f712350 | 618 | } |
avi23 | 5:34855f712350 | 619 | } |
avi23 | 5:34855f712350 | 620 | } |
avi23 | 5:34855f712350 | 621 | |
avi23 | 8:b2faec20ed8f | 622 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 623 | void DrawSingleLargeInvader(int invader_no) |
avi23 | 5:34855f712350 | 624 | { |
avi23 | 5:34855f712350 | 625 | for (int col = 0; col < 12; ++col) { |
avi23 | 5:34855f712350 | 626 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 627 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 628 | if (large_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 629 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = first_large_invader_pixel + invader_no; |
avi23 | 5:34855f712350 | 630 | } |
avi23 | 5:34855f712350 | 631 | } else { |
avi23 | 5:34855f712350 | 632 | if (large_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 633 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = first_large_invader_pixel + invader_no; |
avi23 | 2:d34c95990605 | 634 | } |
avi23 | 2:d34c95990605 | 635 | } |
avi23 | 2:d34c95990605 | 636 | } |
avi23 | 2:d34c95990605 | 637 | } |
avi23 | 2:d34c95990605 | 638 | } |
avi23 | 2:d34c95990605 | 639 | |
avi23 | 8:b2faec20ed8f | 640 | ///Sets the position and loads the bitmap into the barrier objects |
avi23 | 2:d34c95990605 | 641 | void InitBarriers() |
avi23 | 2:d34c95990605 | 642 | { |
avi23 | 5:34855f712350 | 643 | for (int i = 0; i < 3; ++i) { |
avi23 | 2:d34c95990605 | 644 | barrier[i].x_pos = 10 + (i*25); |
avi23 | 2:d34c95990605 | 645 | barrier[i].y_pos = 33; |
avi23 | 8:b2faec20ed8f | 646 | ///Copies the bitmap into the structs |
avi23 | 2:d34c95990605 | 647 | memcpy(barrier[i].before_bitmap, barrier_bitmap, sizeof(barrier_bitmap)); |
avi23 | 2:d34c95990605 | 648 | memcpy(barrier[i].after_bitmap, barrier_bitmap, sizeof(barrier_bitmap)); |
avi23 | 2:d34c95990605 | 649 | } |
avi23 | 2:d34c95990605 | 650 | } |
avi23 | 2:d34c95990605 | 651 | |
avi23 | 2:d34c95990605 | 652 | void DrawBarriers() |
avi23 | 2:d34c95990605 | 653 | { |
avi23 | 8:b2faec20ed8f | 654 | ///Clears the barrier and redraws it with damage applied |
avi23 | 5:34855f712350 | 655 | for (int i = 0; i < 3; ++i) { |
avi23 | 5:34855f712350 | 656 | for (int col = 0; col < 14; ++col) { |
avi23 | 5:34855f712350 | 657 | for (int row = 0; row < 8; ++row) { |
avi23 | 2:d34c95990605 | 658 | if (barrier[i].before_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 659 | screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 660 | } |
avi23 | 2:d34c95990605 | 661 | if (barrier[i].after_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 662 | screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i; |
avi23 | 2:d34c95990605 | 663 | } |
avi23 | 2:d34c95990605 | 664 | } |
avi23 | 2:d34c95990605 | 665 | } |
avi23 | 8:b2faec20ed8f | 666 | ///Copies the after array to the before array |
avi23 | 2:d34c95990605 | 667 | memcpy(barrier[i].before_bitmap, barrier[i].after_bitmap, sizeof(barrier[i].after_bitmap)); |
avi23 | 2:d34c95990605 | 668 | } |
avi23 | 2:d34c95990605 | 669 | } |
avi23 | 2:d34c95990605 | 670 | |
avi23 | 5:34855f712350 | 671 | void MoveInvaderXPositions() |
avi23 | 2:d34c95990605 | 672 | { |
avi23 | 8:b2faec20ed8f | 673 | ///Moves the invader in the current direction |
avi23 | 2:d34c95990605 | 674 | if (invader_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 675 | ///Checking the right limit |
avi23 | 7:babc367a3333 | 676 | int right_invader_limit = CalculateInvaderRightLimit(); |
avi23 | 5:34855f712350 | 677 | MoveInvadersRight(right_invader_limit); |
avi23 | 5:34855f712350 | 678 | } else { |
avi23 | 8:b2faec20ed8f | 679 | ///Checks the left limit |
avi23 | 7:babc367a3333 | 680 | int left_invader_limit = CalculateInvaderLeftLimit(); |
avi23 | 5:34855f712350 | 681 | MoveInvadersLeft(left_invader_limit); |
avi23 | 5:34855f712350 | 682 | } |
avi23 | 5:34855f712350 | 683 | } |
avi23 | 5:34855f712350 | 684 | |
avi23 | 8:b2faec20ed8f | 685 | ///Checks the status off the invaders per column, starting from the left |
avi23 | 8:b2faec20ed8f | 686 | ///If they're alive return the row number |
avi23 | 5:34855f712350 | 687 | int CalculateInvaderLeftLimit() |
avi23 | 5:34855f712350 | 688 | { |
avi23 | 5:34855f712350 | 689 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 690 | if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 691 | return i; |
avi23 | 5:34855f712350 | 692 | } |
avi23 | 5:34855f712350 | 693 | } |
avi23 | 5:34855f712350 | 694 | |
avi23 | 8:b2faec20ed8f | 695 | ///Sort gameover out stuff after |
avi23 | 5:34855f712350 | 696 | return 4; |
avi23 | 5:34855f712350 | 697 | } |
avi23 | 5:34855f712350 | 698 | |
avi23 | 8:b2faec20ed8f | 699 | ///Checks the status off the invaders per column, starting from the right |
avi23 | 8:b2faec20ed8f | 700 | ///If they're alive return the row number |
avi23 | 5:34855f712350 | 701 | int CalculateInvaderRightLimit() |
avi23 | 5:34855f712350 | 702 | { |
avi23 | 5:34855f712350 | 703 | for (int i = 4; i >= 0; --i) { |
avi23 | 5:34855f712350 | 704 | if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 705 | return i; |
avi23 | 5:34855f712350 | 706 | } |
avi23 | 5:34855f712350 | 707 | } |
avi23 | 5:34855f712350 | 708 | |
avi23 | 8:b2faec20ed8f | 709 | ///Sort gameover stuff |
avi23 | 5:34855f712350 | 710 | return 0; |
avi23 | 5:34855f712350 | 711 | } |
avi23 | 5:34855f712350 | 712 | |
avi23 | 5:34855f712350 | 713 | void MoveInvadersLeft(int limit) |
avi23 | 5:34855f712350 | 714 | { |
avi23 | 8:b2faec20ed8f | 715 | ///Checks the first large invader to see if it can travel anymore |
avi23 | 5:34855f712350 | 716 | if (large_invader[limit].x_pos > 1) { |
avi23 | 5:34855f712350 | 717 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 718 | ///Moves the invaders 2 to the left |
avi23 | 5:34855f712350 | 719 | small_invader[i].x_pos -= 2; |
avi23 | 5:34855f712350 | 720 | medium_invader[i].x_pos -= 2; |
avi23 | 5:34855f712350 | 721 | large_invader[i].x_pos -= 2; |
avi23 | 2:d34c95990605 | 722 | } |
avi23 | 2:d34c95990605 | 723 | } else { |
avi23 | 8:b2faec20ed8f | 724 | ///Shifts the Invaders down and passes in the new direction |
avi23 | 5:34855f712350 | 725 | MoveInvaderYPositions(RIGHT); |
avi23 | 2:d34c95990605 | 726 | } |
avi23 | 2:d34c95990605 | 727 | } |
avi23 | 2:d34c95990605 | 728 | |
avi23 | 5:34855f712350 | 729 | void MoveInvadersRight(int limit) |
avi23 | 2:d34c95990605 | 730 | { |
avi23 | 8:b2faec20ed8f | 731 | ///Checks the first large invader to see if it can travel anymore |
avi23 | 5:34855f712350 | 732 | if (large_invader[limit].x_pos < 71) { |
avi23 | 8:b2faec20ed8f | 733 | ///Moves the invaders 2 to the right |
avi23 | 5:34855f712350 | 734 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 735 | small_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 736 | medium_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 737 | large_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 738 | } |
avi23 | 2:d34c95990605 | 739 | } else { |
avi23 | 8:b2faec20ed8f | 740 | ///Shifts the Invaders down and passes in the new direction |
avi23 | 5:34855f712350 | 741 | MoveInvaderYPositions(LEFT); |
avi23 | 2:d34c95990605 | 742 | } |
avi23 | 5:34855f712350 | 743 | } |
avi23 | 5:34855f712350 | 744 | |
avi23 | 5:34855f712350 | 745 | void MoveInvaderYPositions(bool new_direction) |
avi23 | 5:34855f712350 | 746 | { |
avi23 | 8:b2faec20ed8f | 747 | ///Finds the invaders lower limit |
avi23 | 5:34855f712350 | 748 | Invader lowest_invader = CalculateInvaderYLimit(); |
avi23 | 5:34855f712350 | 749 | |
avi23 | 8:b2faec20ed8f | 750 | ///When moving down lowest_invader should not equal none |
avi23 | 5:34855f712350 | 751 | if (lowest_invader == none) { |
avi23 | 5:34855f712350 | 752 | error(); |
avi23 | 5:34855f712350 | 753 | } |
avi23 | 5:34855f712350 | 754 | |
avi23 | 8:b2faec20ed8f | 755 | ///If an invader touches the bottom the game ends, otherwise the invaders descend |
avi23 | 5:34855f712350 | 756 | if (small_invader[0].y_pos < 33 - (7*lowest_invader)) { |
avi23 | 5:34855f712350 | 757 | for (int i = 0; i < 5; ++i) { |
avi23 | 2:d34c95990605 | 758 | small_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 759 | medium_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 760 | large_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 761 | } |
avi23 | 8:b2faec20ed8f | 762 | ++down_count; |
avi23 | 5:34855f712350 | 763 | invader_direction = new_direction; |
avi23 | 5:34855f712350 | 764 | } else { |
avi23 | 5:34855f712350 | 765 | number_of_lives = 0; |
avi23 | 5:34855f712350 | 766 | } |
avi23 | 5:34855f712350 | 767 | } |
avi23 | 5:34855f712350 | 768 | |
avi23 | 5:34855f712350 | 769 | Invader CalculateInvaderYLimit() |
avi23 | 5:34855f712350 | 770 | { |
avi23 | 8:b2faec20ed8f | 771 | ///Checks to see which row of invaders are still alive to work out maximum y positions |
avi23 | 5:34855f712350 | 772 | if (large_invader[0].status == alive || large_invader[1].status == alive || large_invader[2].status == alive || large_invader[3].status == alive || large_invader[4].status == alive) { |
avi23 | 5:34855f712350 | 773 | return large; |
avi23 | 5:34855f712350 | 774 | } else if (medium_invader[0].status == alive || medium_invader[1].status == alive || medium_invader[2].status == alive || medium_invader[3].status == alive || medium_invader[4].status == alive) { |
avi23 | 5:34855f712350 | 775 | return medium; |
avi23 | 2:d34c95990605 | 776 | } else { |
avi23 | 5:34855f712350 | 777 | return small; |
avi23 | 2:d34c95990605 | 778 | } |
avi23 | 5:34855f712350 | 779 | } |
avi23 | 2:d34c95990605 | 780 | |
avi23 | 8:b2faec20ed8f | 781 | ///Queries the invaders on their status and returns the type of invader which is alive |
avi23 | 5:34855f712350 | 782 | Invader LowestInvaderInColumn(int column) |
avi23 | 5:34855f712350 | 783 | { |
avi23 | 5:34855f712350 | 784 | if (large_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 785 | return large; |
avi23 | 5:34855f712350 | 786 | } else if (medium_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 787 | return medium; |
avi23 | 5:34855f712350 | 788 | } else if (small_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 789 | return small; |
avi23 | 5:34855f712350 | 790 | } else { |
avi23 | 5:34855f712350 | 791 | return none; |
avi23 | 5:34855f712350 | 792 | } |
avi23 | 2:d34c95990605 | 793 | } |
avi23 | 2:d34c95990605 | 794 | |
avi23 | 5:34855f712350 | 795 | void FireCannonMissile() |
avi23 | 5:34855f712350 | 796 | { |
avi23 | 8:b2faec20ed8f | 797 | ///Sets the cannon fired flag to true |
avi23 | 5:34855f712350 | 798 | cannon_missile_on_screen = true; |
avi23 | 5:34855f712350 | 799 | |
avi23 | 8:b2faec20ed8f | 800 | ///Offset cannon missile x position by 4 of the cannons x pos |
avi23 | 5:34855f712350 | 801 | cannon_missile_x_pos = cannon_xpos + 4; |
avi23 | 8:b2faec20ed8f | 802 | ///Will always have a starting y of 40 |
avi23 | 5:34855f712350 | 803 | cannon_missile_y_pos = 40; |
avi23 | 8:b2faec20ed8f | 804 | ///Attach the move cannon missile |
avi23 | 5:34855f712350 | 805 | move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); |
avi23 | 5:34855f712350 | 806 | } |
avi23 | 5:34855f712350 | 807 | |
avi23 | 5:34855f712350 | 808 | void MoveCannonMissile() |
avi23 | 5:34855f712350 | 809 | { |
avi23 | 8:b2faec20ed8f | 810 | ///Checks bullet will not go beyond the bounds of the screen buffer |
avi23 | 5:34855f712350 | 811 | if (cannon_missile_y_pos > -1) { |
avi23 | 8:b2faec20ed8f | 812 | ///Loops throught the shot bitmap and clears the pixels in the screen buffer |
avi23 | 5:34855f712350 | 813 | for (int row = 0; row < 4; ++row) { |
avi23 | 8:b2faec20ed8f | 814 | ///Clears the position where the bullet was |
avi23 | 5:34855f712350 | 815 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 816 | } |
avi23 | 5:34855f712350 | 817 | |
avi23 | 8:b2faec20ed8f | 818 | ///Increments the shot going up the screen |
avi23 | 5:34855f712350 | 819 | --cannon_missile_y_pos; |
avi23 | 5:34855f712350 | 820 | |
avi23 | 8:b2faec20ed8f | 821 | ///Checks to see if the shot will hit anything |
avi23 | 5:34855f712350 | 822 | CollisionDetectionCannonMissile(); |
avi23 | 5:34855f712350 | 823 | } else { |
avi23 | 8:b2faec20ed8f | 824 | ///Loops throught the shot bitmap and clears the pixels in the screen buffer |
avi23 | 5:34855f712350 | 825 | for (int row = 1; row < 4; ++row) { |
avi23 | 8:b2faec20ed8f | 826 | ///Clears the position where the bullet was |
avi23 | 5:34855f712350 | 827 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 828 | } |
avi23 | 5:34855f712350 | 829 | |
avi23 | 5:34855f712350 | 830 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 831 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 832 | } |
avi23 | 5:34855f712350 | 833 | } |
avi23 | 5:34855f712350 | 834 | |
avi23 | 8:b2faec20ed8f | 835 | ///Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer |
avi23 | 5:34855f712350 | 836 | void CollisionDetectionCannonMissile() |
avi23 | 5:34855f712350 | 837 | { |
avi23 | 5:34855f712350 | 838 | for (int row = 0; row < 4; ++row) { |
avi23 | 5:34855f712350 | 839 | int object_no; |
avi23 | 7:babc367a3333 | 840 | int pixel_check = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row]; |
avi23 | 8:b2faec20ed8f | 841 | if (pixel_check >= first_small_invader_pixel && pixel_check < ufo_pixel) { ///Collides with a small invader |
avi23 | 8:b2faec20ed8f | 842 | ///Find the object no of the small invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 843 | object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader); |
avi23 | 5:34855f712350 | 844 | ClearSingleSmallInvader(object_no); |
avi23 | 5:34855f712350 | 845 | score += 40; |
avi23 | 5:34855f712350 | 846 | break; |
avi23 | 8:b2faec20ed8f | 847 | } else if (pixel_check >= first_medium_invader_pixel && pixel_check < first_small_invader_pixel) { ///Collides with a medium invader |
avi23 | 8:b2faec20ed8f | 848 | ///Find the object no of the medium invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 849 | object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader); |
avi23 | 5:34855f712350 | 850 | ClearSingleMediumInvader(object_no); |
avi23 | 5:34855f712350 | 851 | score += 20; |
avi23 | 5:34855f712350 | 852 | break; |
avi23 | 8:b2faec20ed8f | 853 | } else if (pixel_check >= first_large_invader_pixel && pixel_check < first_medium_invader_pixel) { ///Collides with a large invader |
avi23 | 8:b2faec20ed8f | 854 | ///Find the object no of the large invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 855 | object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader); |
avi23 | 5:34855f712350 | 856 | ClearSingleLargeInvader(object_no); |
avi23 | 5:34855f712350 | 857 | score += 10; |
avi23 | 5:34855f712350 | 858 | break; |
avi23 | 8:b2faec20ed8f | 859 | } else if (pixel_check >= first_barrier_pixel && pixel_check < (first_barrier_pixel + 3)) { ///Collides with a barrier |
avi23 | 8:b2faec20ed8f | 860 | ///Adds the destruction done to the barrier to the bitmap and redraws the barriers |
avi23 | 7:babc367a3333 | 861 | CannonMissileHitBarrier(row); |
avi23 | 5:34855f712350 | 862 | DrawBarriers(); |
avi23 | 5:34855f712350 | 863 | break; |
avi23 | 8:b2faec20ed8f | 864 | } else if (pixel_check == ufo_pixel) { ///Collides with a UFO |
avi23 | 8:b2faec20ed8f | 865 | ///Clears the UFO, calculates score depending on the ufo bonus |
avi23 | 8:b2faec20ed8f | 866 | ClearUFO(); |
avi23 | 8:b2faec20ed8f | 867 | ufo_on_screen = false; |
avi23 | 8:b2faec20ed8f | 868 | move_ufo.detach(); |
avi23 | 8:b2faec20ed8f | 869 | if (ufo_bonus && shot_count == 15) { ///If the shot bonus is active and on the 15th shot, give 300 points |
avi23 | 8:b2faec20ed8f | 870 | score += 300; |
avi23 | 8:b2faec20ed8f | 871 | } else if (shot_count == 23) { ///If the shot bonus isn't active and on the 23rd shot, give 300 points and activate the bonus |
avi23 | 9:cbb982b7e353 | 872 | ufo_bonus = true; |
avi23 | 9:cbb982b7e353 | 873 | score += 300; |
avi23 | 8:b2faec20ed8f | 874 | } else { ///Randomly assign score between 50, 100, 150 points |
avi23 | 8:b2faec20ed8f | 875 | score += 50 * ((rand() % 3) + 1); |
avi23 | 8:b2faec20ed8f | 876 | } |
avi23 | 5:34855f712350 | 877 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 878 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 879 | break; |
avi23 | 5:34855f712350 | 880 | } else { |
avi23 | 5:34855f712350 | 881 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = cannon_missile_pixel; |
avi23 | 5:34855f712350 | 882 | } |
avi23 | 5:34855f712350 | 883 | } |
avi23 | 5:34855f712350 | 884 | } |
avi23 | 5:34855f712350 | 885 | |
avi23 | 8:b2faec20ed8f | 886 | ///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 |
avi23 | 5:34855f712350 | 887 | int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]) |
avi23 | 5:34855f712350 | 888 | { |
avi23 | 5:34855f712350 | 889 | int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel; |
avi23 | 5:34855f712350 | 890 | invader[invader_no].status = dying; |
avi23 | 5:34855f712350 | 891 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 892 | --no_of_alive_invaders; |
avi23 | 5:34855f712350 | 893 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 894 | |
avi23 | 5:34855f712350 | 895 | return invader_no; |
avi23 | 5:34855f712350 | 896 | } |
avi23 | 5:34855f712350 | 897 | |
avi23 | 8:b2faec20ed8f | 898 | ///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation |
avi23 | 7:babc367a3333 | 899 | void CannonMissileHitBarrier(int row) |
avi23 | 5:34855f712350 | 900 | { |
avi23 | 7:babc367a3333 | 901 | int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_barrier_pixel; |
avi23 | 8:b2faec20ed8f | 902 | ///Essentially inverse of barrier init |
avi23 | 5:34855f712350 | 903 | int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1; |
avi23 | 8:b2faec20ed8f | 904 | int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; ///Don't know why it's -1 and not -2 |
avi23 | 8:b2faec20ed8f | 905 | ///Loops through the damage bitmap and modifies the barrier's after bitmap |
avi23 | 5:34855f712350 | 906 | for (int col = 0; col < 3; ++col) { |
avi23 | 5:34855f712350 | 907 | for (int row_bit = 0; row_bit < 3; ++row_bit) { |
avi23 | 8:b2faec20ed8f | 908 | ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration |
avi23 | 8:b2faec20ed8f | 909 | ///Element by element multiplication of the 2 bitmaps to clear the required pixals |
avi23 | 5:34855f712350 | 910 | if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) { |
avi23 | 5:34855f712350 | 911 | barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_cannon_missile_damage_bitmap[row_bit][col]; |
avi23 | 5:34855f712350 | 912 | } |
avi23 | 5:34855f712350 | 913 | } |
avi23 | 5:34855f712350 | 914 | } |
avi23 | 5:34855f712350 | 915 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 916 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 917 | } |
avi23 | 5:34855f712350 | 918 | |
avi23 | 5:34855f712350 | 919 | void AttemptToFireInvaderNormalMissiles() |
avi23 | 5:34855f712350 | 920 | { |
avi23 | 8:b2faec20ed8f | 921 | ///Fires the normal missiles |
avi23 | 8:b2faec20ed8f | 922 | ///Loops through the 2 allowed missiles and if they're not on the screen, randomly fire |
avi23 | 5:34855f712350 | 923 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 924 | if (!invader_normal_missile[i].fired) { |
avi23 | 8:b2faec20ed8f | 925 | ///If the random mumber is 1, fire a missile |
avi23 | 8:b2faec20ed8f | 926 | ///Higher chance when there are less invaders on the screen, up to a 1/3 chance |
avi23 | 5:34855f712350 | 927 | if ((rand() % (no_of_alive_invaders + 2)) == 1) { |
avi23 | 5:34855f712350 | 928 | int fired_column; |
avi23 | 8:b2faec20ed8f | 929 | int loop_limit = 0; ///Stops loop from never ending |
avi23 | 5:34855f712350 | 930 | Invader missile_source; |
avi23 | 5:34855f712350 | 931 | do { |
avi23 | 5:34855f712350 | 932 | fired_column = rand() % 5; |
avi23 | 5:34855f712350 | 933 | missile_source = LowestInvaderInColumn(fired_column); |
avi23 | 5:34855f712350 | 934 | ++loop_limit; |
avi23 | 5:34855f712350 | 935 | } while (missile_source == none && loop_limit < 10); |
avi23 | 5:34855f712350 | 936 | |
avi23 | 8:b2faec20ed8f | 937 | ///Finds the centre point of the chosen invader and fires the missile |
avi23 | 8:b2faec20ed8f | 938 | ///If the loop limit is reached, the missile source will be none and the for loop will jump to the next iteration |
avi23 | 5:34855f712350 | 939 | if (missile_source == none) { |
avi23 | 5:34855f712350 | 940 | continue; |
avi23 | 5:34855f712350 | 941 | } else if (missile_source == large) { |
avi23 | 5:34855f712350 | 942 | FireNormalInvaderMissile(i, missile_source, large_invader[fired_column]); |
avi23 | 5:34855f712350 | 943 | } else if (missile_source == medium) { |
avi23 | 5:34855f712350 | 944 | FireNormalInvaderMissile(i, missile_source, medium_invader[fired_column]); |
avi23 | 5:34855f712350 | 945 | } else { |
avi23 | 5:34855f712350 | 946 | FireNormalInvaderMissile(i, missile_source, small_invader[fired_column]); |
avi23 | 5:34855f712350 | 947 | } |
avi23 | 5:34855f712350 | 948 | } |
avi23 | 5:34855f712350 | 949 | } |
avi23 | 5:34855f712350 | 950 | } |
avi23 | 5:34855f712350 | 951 | } |
avi23 | 5:34855f712350 | 952 | |
avi23 | 5:34855f712350 | 953 | void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader)) |
avi23 | 5:34855f712350 | 954 | { |
avi23 | 8:b2faec20ed8f | 955 | ///Finds the centre point of the chosen invader and fires the missile |
avi23 | 8:b2faec20ed8f | 956 | ///Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3 |
avi23 | 5:34855f712350 | 957 | invader_normal_missile[missile_no].x_pos = invader.x_pos + (3 + source); |
avi23 | 5:34855f712350 | 958 | invader_normal_missile[missile_no].y_pos = invader.y_pos + 6; |
avi23 | 5:34855f712350 | 959 | invader_normal_missile[missile_no].fired = true; |
avi23 | 5:34855f712350 | 960 | |
avi23 | 8:b2faec20ed8f | 961 | ///Uses a function pointer to attach the ticker |
avi23 | 5:34855f712350 | 962 | move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05); |
avi23 | 5:34855f712350 | 963 | } |
avi23 | 5:34855f712350 | 964 | |
avi23 | 7:babc367a3333 | 965 | void MoveInvaderNormalMissile(int missile_no) |
avi23 | 7:babc367a3333 | 966 | { |
avi23 | 8:b2faec20ed8f | 967 | ///Loops through the bitmap and clears the missile from the screen buffer |
avi23 | 7:babc367a3333 | 968 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 969 | for (int row = 0; row < 4; ++row) { |
avi23 | 7:babc367a3333 | 970 | if (invader_normal_missile_bitmap[row][col]) { |
avi23 | 7:babc367a3333 | 971 | screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel; |
avi23 | 7:babc367a3333 | 972 | } |
avi23 | 7:babc367a3333 | 973 | } |
avi23 | 7:babc367a3333 | 974 | } |
avi23 | 7:babc367a3333 | 975 | |
avi23 | 8:b2faec20ed8f | 976 | ///Checks missile will not exceed screen buffer |
avi23 | 7:babc367a3333 | 977 | if (invader_normal_missile[missile_no].y_pos < 44) { |
avi23 | 8:b2faec20ed8f | 978 | ///Increments the position of the missile |
avi23 | 7:babc367a3333 | 979 | ++invader_normal_missile[missile_no].y_pos; |
avi23 | 7:babc367a3333 | 980 | |
avi23 | 8:b2faec20ed8f | 981 | ///Collision detection |
avi23 | 7:babc367a3333 | 982 | CollisionDetectionInvaderNormalMissile(missile_no); |
avi23 | 7:babc367a3333 | 983 | |
avi23 | 7:babc367a3333 | 984 | } else { |
avi23 | 8:b2faec20ed8f | 985 | ///Sets the missiles fired flag as false and detaches the tickers |
avi23 | 7:babc367a3333 | 986 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 987 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 988 | } |
avi23 | 7:babc367a3333 | 989 | } |
avi23 | 7:babc367a3333 | 990 | |
avi23 | 8:b2faec20ed8f | 991 | ///Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer |
avi23 | 7:babc367a3333 | 992 | void CollisionDetectionInvaderNormalMissile(int missile_no) |
avi23 | 7:babc367a3333 | 993 | { |
avi23 | 8:b2faec20ed8f | 994 | ///Invader missile coordinates shifted to match centre bottom of bitmap |
avi23 | 7:babc367a3333 | 995 | int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1; |
avi23 | 7:babc367a3333 | 996 | int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3; |
avi23 | 7:babc367a3333 | 997 | if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) { |
avi23 | 9:cbb982b7e353 | 998 | ///Cannon has invunerability for 1s after getting hit |
avi23 | 9:cbb982b7e353 | 999 | if (!g_cannon_hit_flag) { |
avi23 | 9:cbb982b7e353 | 1000 | g_cannon_hit_flag = true; |
avi23 | 9:cbb982b7e353 | 1001 | InvaderNormalMissileHitCannon(); |
avi23 | 9:cbb982b7e353 | 1002 | ///Attaches a timeout to allow cannon to be hit again |
avi23 | 9:cbb982b7e353 | 1003 | cannon_hit.attach(&cannon_hit_isr, 1); |
avi23 | 9:cbb982b7e353 | 1004 | } |
avi23 | 7:babc367a3333 | 1005 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 1006 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 1007 | } 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)) { |
avi23 | 8:b2faec20ed8f | 1008 | ///Finds barrier number |
avi23 | 7:babc367a3333 | 1009 | InvaderNormalMissileHitBarrier(invader_normal_missile[missile_no]); |
avi23 | 7:babc367a3333 | 1010 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 1011 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 1012 | } else { |
avi23 | 7:babc367a3333 | 1013 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 1014 | for (int row = 0; row < 4; ++row) { |
avi23 | 7:babc367a3333 | 1015 | if (invader_normal_missile_bitmap[row][col]) { |
avi23 | 7:babc367a3333 | 1016 | screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = invader_normal_missile_pixel; |
avi23 | 7:babc367a3333 | 1017 | } |
avi23 | 7:babc367a3333 | 1018 | } |
avi23 | 7:babc367a3333 | 1019 | } |
avi23 | 7:babc367a3333 | 1020 | } |
avi23 | 7:babc367a3333 | 1021 | } |
avi23 | 7:babc367a3333 | 1022 | |
avi23 | 7:babc367a3333 | 1023 | void InvaderNormalMissileHitCannon() |
avi23 | 7:babc367a3333 | 1024 | { |
avi23 | 8:b2faec20ed8f | 1025 | ///Decrements the number of lives, pauses the game for 2 seconds |
avi23 | 8:b2faec20ed8f | 1026 | ///Detaches all tickers |
avi23 | 7:babc367a3333 | 1027 | DetachTickers(); |
avi23 | 9:cbb982b7e353 | 1028 | LPWait(2); |
avi23 | 7:babc367a3333 | 1029 | --number_of_lives; |
avi23 | 9:cbb982b7e353 | 1030 | AttachTickers(); |
avi23 | 7:babc367a3333 | 1031 | } |
avi23 | 7:babc367a3333 | 1032 | |
avi23 | 8:b2faec20ed8f | 1033 | ///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation |
avi23 | 7:babc367a3333 | 1034 | void InvaderNormalMissileHitBarrier(const struct InvaderNormalMissiles (&missile)) |
avi23 | 7:babc367a3333 | 1035 | { |
avi23 | 7:babc367a3333 | 1036 | int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_barrier_pixel; |
avi23 | 8:b2faec20ed8f | 1037 | ///Essentially inverse of barrier init |
avi23 | 7:babc367a3333 | 1038 | int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1; |
avi23 | 7:babc367a3333 | 1039 | int relative_y_pos = (missile.y_pos + 3) - 33; |
avi23 | 8:b2faec20ed8f | 1040 | ///Loops through the damage bitmap and modifies the barrier's after bitmap |
avi23 | 7:babc367a3333 | 1041 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 1042 | for (int row_bit = 0; row_bit < 2; ++row_bit) { |
avi23 | 8:b2faec20ed8f | 1043 | ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration |
avi23 | 7:babc367a3333 | 1044 | if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) { |
avi23 | 7:babc367a3333 | 1045 | barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col]; |
avi23 | 7:babc367a3333 | 1046 | } |
avi23 | 7:babc367a3333 | 1047 | } |
avi23 | 7:babc367a3333 | 1048 | } |
avi23 | 7:babc367a3333 | 1049 | } |
avi23 | 7:babc367a3333 | 1050 | |
avi23 | 8:b2faec20ed8f | 1051 | ///Detaches game related tickers |
avi23 | 5:34855f712350 | 1052 | void DetachTickers() |
avi23 | 5:34855f712350 | 1053 | { |
avi23 | 5:34855f712350 | 1054 | update_screen.detach(); |
avi23 | 5:34855f712350 | 1055 | move_enemies.detach(); |
avi23 | 8:b2faec20ed8f | 1056 | |
avi23 | 9:cbb982b7e353 | 1057 | ///Only detaches if are on the screen |
avi23 | 5:34855f712350 | 1058 | if (cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 1059 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 1060 | } |
avi23 | 9:cbb982b7e353 | 1061 | if (ufo_on_screen) { |
avi23 | 9:cbb982b7e353 | 1062 | move_ufo.detach(); |
avi23 | 9:cbb982b7e353 | 1063 | } |
avi23 | 5:34855f712350 | 1064 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 1065 | if (invader_normal_missile[i].fired) { |
avi23 | 5:34855f712350 | 1066 | move_invader_normal_missile[i].detach(); |
avi23 | 5:34855f712350 | 1067 | } |
avi23 | 5:34855f712350 | 1068 | } |
avi23 | 5:34855f712350 | 1069 | } |
avi23 | 5:34855f712350 | 1070 | |
avi23 | 8:b2faec20ed8f | 1071 | ///Attaches game related tickers |
avi23 | 5:34855f712350 | 1072 | void AttachTickers() |
avi23 | 5:34855f712350 | 1073 | { |
avi23 | 5:34855f712350 | 1074 | update_screen.attach(&update_screen_isr, 0.05); |
avi23 | 5:34855f712350 | 1075 | move_enemies.attach(&move_enemies_isr, ticker_period); |
avi23 | 8:b2faec20ed8f | 1076 | ///Only attaches if missiles were on the screen |
avi23 | 5:34855f712350 | 1077 | if (cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 1078 | move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); |
avi23 | 5:34855f712350 | 1079 | } |
avi23 | 9:cbb982b7e353 | 1080 | if (ufo_on_screen) { |
avi23 | 9:cbb982b7e353 | 1081 | move_ufo.attach(&move_ufo_isr, 0.1); |
avi23 | 9:cbb982b7e353 | 1082 | } |
avi23 | 5:34855f712350 | 1083 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 1084 | if (invader_normal_missile[i].fired) { |
avi23 | 5:34855f712350 | 1085 | move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05); |
avi23 | 5:34855f712350 | 1086 | } |
avi23 | 5:34855f712350 | 1087 | } |
avi23 | 6:89d4a7f7588b | 1088 | } |
avi23 | 6:89d4a7f7588b | 1089 | |
avi23 | 6:89d4a7f7588b | 1090 | void PauseScreen() |
avi23 | 6:89d4a7f7588b | 1091 | { |
avi23 | 8:b2faec20ed8f | 1092 | ///Prints the pause screen, score etc |
avi23 | 7:babc367a3333 | 1093 | PrintPauseScreen(); |
avi23 | 7:babc367a3333 | 1094 | |
avi23 | 6:89d4a7f7588b | 1095 | while (game_state == paused) { |
avi23 | 8:b2faec20ed8f | 1096 | ///Draws the cursor |
avi23 | 8:b2faec20ed8f | 1097 | 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 |
avi23 | 8:b2faec20ed8f | 1098 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); ///Draws the cursor |
avi23 | 6:89d4a7f7588b | 1099 | |
avi23 | 6:89d4a7f7588b | 1100 | if (g_move_joystick_flag) { |
avi23 | 6:89d4a7f7588b | 1101 | g_move_joystick_flag = false; |
avi23 | 6:89d4a7f7588b | 1102 | |
avi23 | 8:b2faec20ed8f | 1103 | ///Moves the cursor to match the selected option, only if the joystick isn't centred |
avi23 | 6:89d4a7f7588b | 1104 | MoveCursor(fsm_paused); |
avi23 | 6:89d4a7f7588b | 1105 | } |
avi23 | 6:89d4a7f7588b | 1106 | |
avi23 | 8:b2faec20ed8f | 1107 | ///If the button is pressed the selected option will appear on the screen |
avi23 | 6:89d4a7f7588b | 1108 | if (g_shoot_pressed_flag) { |
avi23 | 6:89d4a7f7588b | 1109 | g_shoot_pressed_flag = false; |
avi23 | 9:cbb982b7e353 | 1110 | |
avi23 | 6:89d4a7f7588b | 1111 | game_state = fsm_paused[fsm_state].output; |
avi23 | 6:89d4a7f7588b | 1112 | } |
avi23 | 6:89d4a7f7588b | 1113 | |
avi23 | 9:cbb982b7e353 | 1114 | ///Returns to the game state when the joystick is pressed |
avi23 | 6:89d4a7f7588b | 1115 | if (joystick.get_button_flag()) { |
avi23 | 6:89d4a7f7588b | 1116 | joystick.set_button_flag(0); |
avi23 | 9:cbb982b7e353 | 1117 | |
avi23 | 9:cbb982b7e353 | 1118 | game_state = game; |
avi23 | 6:89d4a7f7588b | 1119 | } |
avi23 | 6:89d4a7f7588b | 1120 | |
avi23 | 6:89d4a7f7588b | 1121 | lcd.refresh(); |
avi23 | 6:89d4a7f7588b | 1122 | sleep(); |
avi23 | 6:89d4a7f7588b | 1123 | } |
avi23 | 6:89d4a7f7588b | 1124 | } |
avi23 | 6:89d4a7f7588b | 1125 | |
avi23 | 6:89d4a7f7588b | 1126 | void PrintPauseScreen() |
avi23 | 6:89d4a7f7588b | 1127 | { |
avi23 | 8:b2faec20ed8f | 1128 | ///Prints paused and a line underneath |
avi23 | 6:89d4a7f7588b | 1129 | lcd.printString("Paused", 24, 0); |
avi23 | 8:b2faec20ed8f | 1130 | ///Displays the current score |
avi23 | 6:89d4a7f7588b | 1131 | char buffer[14]; |
avi23 | 6:89d4a7f7588b | 1132 | sprintf(buffer, "Score: %d", score); |
avi23 | 6:89d4a7f7588b | 1133 | lcd.printString(buffer, 0, 1); |
avi23 | 8:b2faec20ed8f | 1134 | ///Displays the no of lives |
avi23 | 6:89d4a7f7588b | 1135 | sprintf(buffer, "Lives: %d", number_of_lives); |
avi23 | 6:89d4a7f7588b | 1136 | lcd.printString(buffer, 0, 2); |
avi23 | 6:89d4a7f7588b | 1137 | lcd.drawLine(0, 23, 83, 23, 2); |
avi23 | 8:b2faec20ed8f | 1138 | ///Prints options on pause menu |
avi23 | 6:89d4a7f7588b | 1139 | lcd.printString("Resume", 5, 3); |
avi23 | 6:89d4a7f7588b | 1140 | lcd.printString("Save", 5, 4); |
avi23 | 6:89d4a7f7588b | 1141 | lcd.printString("Quit", 5, 5); |
avi23 | 6:89d4a7f7588b | 1142 | } |
avi23 | 6:89d4a7f7588b | 1143 | |
avi23 | 6:89d4a7f7588b | 1144 | void MoveCursor(const struct FSMMenus *fsm) |
avi23 | 6:89d4a7f7588b | 1145 | { |
avi23 | 8:b2faec20ed8f | 1146 | ///If the joystick is is pushed down half way clear the cursor and set the next state |
avi23 | 6:89d4a7f7588b | 1147 | if (joystick.GetYValue() < 0.25f) { |
avi23 | 8:b2faec20ed8f | 1148 | ///Clears the cursor |
avi23 | 6:89d4a7f7588b | 1149 | lcd.drawRect(74, cursor_y_pos, 2, 2, 2); |
avi23 | 8:b2faec20ed8f | 1150 | ///Sets the new state |
avi23 | 6:89d4a7f7588b | 1151 | fsm_state = fsm[fsm_state].next_state[0]; |
avi23 | 6:89d4a7f7588b | 1152 | } else if (joystick.GetYValue() > 0.75f) { |
avi23 | 8:b2faec20ed8f | 1153 | ///Clears the cursor |
avi23 | 6:89d4a7f7588b | 1154 | lcd.drawRect(74, cursor_y_pos, 2, 2, 2); |
avi23 | 8:b2faec20ed8f | 1155 | ///Sets the new state |
avi23 | 6:89d4a7f7588b | 1156 | fsm_state = fsm[fsm_state].next_state[1]; |
avi23 | 6:89d4a7f7588b | 1157 | } |
avi23 | 8:b2faec20ed8f | 1158 | } |
avi23 | 8:b2faec20ed8f | 1159 | |
avi23 | 8:b2faec20ed8f | 1160 | void MenuScreen() |
avi23 | 8:b2faec20ed8f | 1161 | { |
avi23 | 8:b2faec20ed8f | 1162 | ///Print the menu text |
avi23 | 8:b2faec20ed8f | 1163 | PrintMenuScreen(); |
avi23 | 8:b2faec20ed8f | 1164 | |
avi23 | 8:b2faec20ed8f | 1165 | while (game_state == menu) { |
avi23 | 8:b2faec20ed8f | 1166 | ///Draws the cursor |
avi23 | 8:b2faec20ed8f | 1167 | 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 |
avi23 | 8:b2faec20ed8f | 1168 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); |
avi23 | 8:b2faec20ed8f | 1169 | |
avi23 | 8:b2faec20ed8f | 1170 | if (g_move_joystick_flag) { |
avi23 | 8:b2faec20ed8f | 1171 | g_move_joystick_flag = false; |
avi23 | 8:b2faec20ed8f | 1172 | |
avi23 | 8:b2faec20ed8f | 1173 | ///Moves the cursor to match the selected option, only if the joystick isn't centred |
avi23 | 8:b2faec20ed8f | 1174 | MoveCursor(fsm_main_menu); |
avi23 | 8:b2faec20ed8f | 1175 | } |
avi23 | 8:b2faec20ed8f | 1176 | |
avi23 | 8:b2faec20ed8f | 1177 | ///If shoot is pressed go to the selected screen |
avi23 | 8:b2faec20ed8f | 1178 | if (g_shoot_pressed_flag) { |
avi23 | 8:b2faec20ed8f | 1179 | g_shoot_pressed_flag = false; |
avi23 | 8:b2faec20ed8f | 1180 | |
avi23 | 8:b2faec20ed8f | 1181 | game_state = fsm_main_menu[fsm_state].output; |
avi23 | 8:b2faec20ed8f | 1182 | |
avi23 | 8:b2faec20ed8f | 1183 | ///If the game state is equal to the game initalise it |
avi23 | 8:b2faec20ed8f | 1184 | if (game_state == game) { |
avi23 | 8:b2faec20ed8f | 1185 | InitaliseGame(); |
avi23 | 8:b2faec20ed8f | 1186 | } |
avi23 | 8:b2faec20ed8f | 1187 | } |
avi23 | 8:b2faec20ed8f | 1188 | |
avi23 | 8:b2faec20ed8f | 1189 | ///Do nothing when the joystick is pressed |
avi23 | 8:b2faec20ed8f | 1190 | if(joystick.get_button_flag()) { |
avi23 | 8:b2faec20ed8f | 1191 | joystick.set_button_flag(0); |
avi23 | 8:b2faec20ed8f | 1192 | } |
avi23 | 8:b2faec20ed8f | 1193 | |
avi23 | 8:b2faec20ed8f | 1194 | lcd.refresh(); |
avi23 | 8:b2faec20ed8f | 1195 | sleep(); |
avi23 | 8:b2faec20ed8f | 1196 | } |
avi23 | 8:b2faec20ed8f | 1197 | } |
avi23 | 8:b2faec20ed8f | 1198 | |
avi23 | 8:b2faec20ed8f | 1199 | void PrintMenuScreen() |
avi23 | 8:b2faec20ed8f | 1200 | { |
avi23 | 8:b2faec20ed8f | 1201 | ///Prints Space invaders, then menu below, then a line underneath |
avi23 | 8:b2faec20ed8f | 1202 | lcd.printString("Space Invaders", 0, 0); |
avi23 | 8:b2faec20ed8f | 1203 | lcd.printString("Menu", 28, 1); |
avi23 | 8:b2faec20ed8f | 1204 | lcd.drawLine(0, 15, 83, 15, 2); |
avi23 | 8:b2faec20ed8f | 1205 | |
avi23 | 8:b2faec20ed8f | 1206 | ///Prints menu options |
avi23 | 8:b2faec20ed8f | 1207 | lcd.printString("New Game", 5, 2); |
avi23 | 8:b2faec20ed8f | 1208 | lcd.printString("Load Game", 5, 3); |
avi23 | 8:b2faec20ed8f | 1209 | lcd.printString("High Scores", 5, 4); |
avi23 | 8:b2faec20ed8f | 1210 | lcd.printString("Settings", 5, 5); |
avi23 | 8:b2faec20ed8f | 1211 | } |
avi23 | 8:b2faec20ed8f | 1212 | |
avi23 | 8:b2faec20ed8f | 1213 | void AttemptToSpawnUFO() |
avi23 | 8:b2faec20ed8f | 1214 | { |
avi23 | 8:b2faec20ed8f | 1215 | ///1/8 chance of UFO spawning if it hasn't already |
avi23 | 8:b2faec20ed8f | 1216 | if (!ufo_on_screen && (rand() % 8 == 1) && down_count > 1 && no_of_alive_invaders > 3) { |
avi23 | 8:b2faec20ed8f | 1217 | ///Marks the UFO as on the screen and sets its position and direction |
avi23 | 8:b2faec20ed8f | 1218 | ufo_on_screen = true; |
avi23 | 8:b2faec20ed8f | 1219 | ufo_direction = (rand() % 2); |
avi23 | 8:b2faec20ed8f | 1220 | if (ufo_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 1221 | ufo_x_pos = -14; |
avi23 | 8:b2faec20ed8f | 1222 | } else { |
avi23 | 8:b2faec20ed8f | 1223 | ufo_x_pos = 83; |
avi23 | 8:b2faec20ed8f | 1224 | } |
avi23 | 8:b2faec20ed8f | 1225 | |
avi23 | 8:b2faec20ed8f | 1226 | ///Attachs the move UFO ticker |
avi23 | 8:b2faec20ed8f | 1227 | move_ufo.attach(&move_ufo_isr, 0.1); |
avi23 | 8:b2faec20ed8f | 1228 | } |
avi23 | 8:b2faec20ed8f | 1229 | } |
avi23 | 8:b2faec20ed8f | 1230 | |
avi23 | 8:b2faec20ed8f | 1231 | void ClearUFO() |
avi23 | 8:b2faec20ed8f | 1232 | { |
avi23 | 8:b2faec20ed8f | 1233 | ///Clears the UFO |
avi23 | 8:b2faec20ed8f | 1234 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 1235 | for (int row = 0; row < 5; ++row) { |
avi23 | 8:b2faec20ed8f | 1236 | ///Only clear the pixel in the buffer if it is within bounds |
avi23 | 8:b2faec20ed8f | 1237 | if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) { |
avi23 | 8:b2faec20ed8f | 1238 | if (ufo_bitmap[row][col]) { |
avi23 | 8:b2faec20ed8f | 1239 | screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = empty_pixel; |
avi23 | 8:b2faec20ed8f | 1240 | } |
avi23 | 8:b2faec20ed8f | 1241 | } |
avi23 | 8:b2faec20ed8f | 1242 | } |
avi23 | 8:b2faec20ed8f | 1243 | } |
avi23 | 8:b2faec20ed8f | 1244 | } |
avi23 | 8:b2faec20ed8f | 1245 | |
avi23 | 8:b2faec20ed8f | 1246 | void DrawUFO() |
avi23 | 8:b2faec20ed8f | 1247 | { |
avi23 | 8:b2faec20ed8f | 1248 | ///Checks if the ufo can be within the screen bounds |
avi23 | 8:b2faec20ed8f | 1249 | ///If it is, push the ufo to the screen buffer |
avi23 | 8:b2faec20ed8f | 1250 | if (ufo_x_pos > -14 && ufo_x_pos < 84) { |
avi23 | 8:b2faec20ed8f | 1251 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 1252 | for (int row = 0; row < 5; ++row) { |
avi23 | 8:b2faec20ed8f | 1253 | ///Only clear the pixel in the buffer if it is within bounds |
avi23 | 8:b2faec20ed8f | 1254 | if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) { |
avi23 | 8:b2faec20ed8f | 1255 | if (ufo_bitmap[row][col]) { |
avi23 | 8:b2faec20ed8f | 1256 | screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = ufo_pixel; |
avi23 | 8:b2faec20ed8f | 1257 | } |
avi23 | 8:b2faec20ed8f | 1258 | } |
avi23 | 8:b2faec20ed8f | 1259 | } |
avi23 | 8:b2faec20ed8f | 1260 | } |
avi23 | 8:b2faec20ed8f | 1261 | } else { |
avi23 | 8:b2faec20ed8f | 1262 | ///Otherwise mark it as not on the screen and detach the ticker |
avi23 | 8:b2faec20ed8f | 1263 | ufo_on_screen = false; |
avi23 | 8:b2faec20ed8f | 1264 | move_ufo.detach(); |
avi23 | 8:b2faec20ed8f | 1265 | } |
avi23 | 9:cbb982b7e353 | 1266 | } |
avi23 | 9:cbb982b7e353 | 1267 | |
avi23 | 9:cbb982b7e353 | 1268 | bool high_scores_sorter(const struct HighScores (&lhs), const struct HighScores (&rhs)) |
avi23 | 9:cbb982b7e353 | 1269 | { |
avi23 | 9:cbb982b7e353 | 1270 | return lhs.score > rhs.score; |
avi23 | 9:cbb982b7e353 | 1271 | } |
avi23 | 9:cbb982b7e353 | 1272 | |
avi23 | 9:cbb982b7e353 | 1273 | void ScoreScreen() |
avi23 | 9:cbb982b7e353 | 1274 | { |
avi23 | 9:cbb982b7e353 | 1275 | lcd.printString("High Scores", 8, 0); |
avi23 | 9:cbb982b7e353 | 1276 | lcd.drawLine(0, 7, 83, 7, 2); |
avi23 | 9:cbb982b7e353 | 1277 | |
avi23 | 9:cbb982b7e353 | 1278 | PrintHighScores(); |
avi23 | 9:cbb982b7e353 | 1279 | |
avi23 | 9:cbb982b7e353 | 1280 | lcd.printString("Back", 5, 5); |
avi23 | 9:cbb982b7e353 | 1281 | const int cursor_y_pos = 43; |
avi23 | 9:cbb982b7e353 | 1282 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); |
avi23 | 9:cbb982b7e353 | 1283 | |
avi23 | 9:cbb982b7e353 | 1284 | lcd.refresh(); |
avi23 | 9:cbb982b7e353 | 1285 | |
avi23 | 9:cbb982b7e353 | 1286 | while (game_state == scores) { |
avi23 | 9:cbb982b7e353 | 1287 | if (joystick.get_button_flag()) { |
avi23 | 9:cbb982b7e353 | 1288 | joystick.set_button_flag(0); |
avi23 | 9:cbb982b7e353 | 1289 | } |
avi23 | 9:cbb982b7e353 | 1290 | if (g_shoot_pressed_flag) { |
avi23 | 9:cbb982b7e353 | 1291 | g_shoot_pressed_flag = false; |
avi23 | 9:cbb982b7e353 | 1292 | |
avi23 | 9:cbb982b7e353 | 1293 | game_state = menu; // If the button is pressed go to the menu state |
avi23 | 9:cbb982b7e353 | 1294 | } |
avi23 | 9:cbb982b7e353 | 1295 | |
avi23 | 9:cbb982b7e353 | 1296 | sleep(); |
avi23 | 9:cbb982b7e353 | 1297 | } |
avi23 | 9:cbb982b7e353 | 1298 | } |
avi23 | 9:cbb982b7e353 | 1299 | |
avi23 | 9:cbb982b7e353 | 1300 | void PrintHighScores() |
avi23 | 9:cbb982b7e353 | 1301 | { |
avi23 | 9:cbb982b7e353 | 1302 | ///Loops throught the high scores and prints them to the screen |
avi23 | 9:cbb982b7e353 | 1303 | for (int i = 0; i < 3; ++i) { |
avi23 | 9:cbb982b7e353 | 1304 | ///Counts how many digits are in score |
avi23 | 9:cbb982b7e353 | 1305 | int temp_score = high_scores[i].score; |
avi23 | 9:cbb982b7e353 | 1306 | int no_of_digits = 0; |
avi23 | 9:cbb982b7e353 | 1307 | do { |
avi23 | 9:cbb982b7e353 | 1308 | temp_score /= 10; |
avi23 | 9:cbb982b7e353 | 1309 | ++no_of_digits; |
avi23 | 9:cbb982b7e353 | 1310 | } while (temp_score != 0); |
avi23 | 9:cbb982b7e353 | 1311 | |
avi23 | 9:cbb982b7e353 | 1312 | ///Prints name to c-string |
avi23 | 9:cbb982b7e353 | 1313 | char buffer[14]; |
avi23 | 9:cbb982b7e353 | 1314 | sprintf(buffer, "%s", high_scores[i].name); |
avi23 | 9:cbb982b7e353 | 1315 | |
avi23 | 9:cbb982b7e353 | 1316 | ///Prints correct number of spaces to c-string |
avi23 | 9:cbb982b7e353 | 1317 | int no_of_spaces = 14 - no_of_digits; |
avi23 | 9:cbb982b7e353 | 1318 | for (int space = 3; space < no_of_spaces; ++space) { |
avi23 | 9:cbb982b7e353 | 1319 | sprintf(buffer, "%s%s", buffer, " "); |
avi23 | 9:cbb982b7e353 | 1320 | } |
avi23 | 9:cbb982b7e353 | 1321 | |
avi23 | 9:cbb982b7e353 | 1322 | ///Prints score to c-string |
avi23 | 9:cbb982b7e353 | 1323 | sprintf(buffer, "%s%d", buffer, high_scores[i].score); |
avi23 | 9:cbb982b7e353 | 1324 | lcd.printString(buffer, 0, 2 + i); |
avi23 | 9:cbb982b7e353 | 1325 | } |
avi23 | 9:cbb982b7e353 | 1326 | } |
avi23 | 9:cbb982b7e353 | 1327 | |
avi23 | 9:cbb982b7e353 | 1328 | void GameOverScreen() |
avi23 | 9:cbb982b7e353 | 1329 | { |
avi23 | 9:cbb982b7e353 | 1330 | lcd.printString("Game Over", 18, 0); |
avi23 | 9:cbb982b7e353 | 1331 | char buffer[14]; |
avi23 | 9:cbb982b7e353 | 1332 | sprintf(buffer, "Score: %d", score); |
avi23 | 9:cbb982b7e353 | 1333 | lcd.printString(buffer, 0, 1); |
avi23 | 9:cbb982b7e353 | 1334 | |
avi23 | 9:cbb982b7e353 | 1335 | ///Save score input |
avi23 | 9:cbb982b7e353 | 1336 | if (score > high_scores[2].score) { |
avi23 | 9:cbb982b7e353 | 1337 | lcd.printString("High Score!", 0, 2); |
avi23 | 9:cbb982b7e353 | 1338 | lcd.printChar('A', 27, 3); |
avi23 | 9:cbb982b7e353 | 1339 | lcd.printChar('A', 42, 3); |
avi23 | 9:cbb982b7e353 | 1340 | lcd.printChar('A', 57, 3); |
avi23 | 9:cbb982b7e353 | 1341 | |
avi23 | 9:cbb982b7e353 | 1342 | int name[3] = {0, 0, 0}; |
avi23 | 9:cbb982b7e353 | 1343 | GetNameForScore(name); |
avi23 | 9:cbb982b7e353 | 1344 | |
avi23 | 9:cbb982b7e353 | 1345 | SaveHighScore(name); |
avi23 | 9:cbb982b7e353 | 1346 | } |
avi23 | 9:cbb982b7e353 | 1347 | |
avi23 | 9:cbb982b7e353 | 1348 | ///After high score is inputted or no high score has been reached |
avi23 | 9:cbb982b7e353 | 1349 | lcd.printString("Quit", 5, 5); |
avi23 | 9:cbb982b7e353 | 1350 | const int cursor_y_pos = 43; |
avi23 | 9:cbb982b7e353 | 1351 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); |
avi23 | 9:cbb982b7e353 | 1352 | |
avi23 | 9:cbb982b7e353 | 1353 | while (game_state == over) { |
avi23 | 9:cbb982b7e353 | 1354 | if (joystick.get_button_flag()) { |
avi23 | 9:cbb982b7e353 | 1355 | joystick.set_button_flag(0); |
avi23 | 9:cbb982b7e353 | 1356 | } |
avi23 | 9:cbb982b7e353 | 1357 | |
avi23 | 9:cbb982b7e353 | 1358 | if (g_shoot_pressed_flag) { |
avi23 | 9:cbb982b7e353 | 1359 | g_shoot_pressed_flag = false; |
avi23 | 9:cbb982b7e353 | 1360 | |
avi23 | 9:cbb982b7e353 | 1361 | game_state = menu; |
avi23 | 9:cbb982b7e353 | 1362 | } |
avi23 | 9:cbb982b7e353 | 1363 | |
avi23 | 9:cbb982b7e353 | 1364 | lcd.refresh(); |
avi23 | 9:cbb982b7e353 | 1365 | sleep(); |
avi23 | 9:cbb982b7e353 | 1366 | } |
avi23 | 9:cbb982b7e353 | 1367 | } |
avi23 | 9:cbb982b7e353 | 1368 | |
avi23 | 9:cbb982b7e353 | 1369 | void GetNameForScore(int (&name)[3]) |
avi23 | 9:cbb982b7e353 | 1370 | { |
avi23 | 9:cbb982b7e353 | 1371 | int name_cursor_pos = 0; ///Cursor is at first letter |
avi23 | 9:cbb982b7e353 | 1372 | |
avi23 | 9:cbb982b7e353 | 1373 | while (name_cursor_pos < 3) { |
avi23 | 9:cbb982b7e353 | 1374 | ///Prints the name cursor |
avi23 | 9:cbb982b7e353 | 1375 | lcd.drawRect(27+(15*name_cursor_pos), 32, 4, 2, 1); |
avi23 | 9:cbb982b7e353 | 1376 | |
avi23 | 9:cbb982b7e353 | 1377 | if (g_shoot_pressed_flag) { |
avi23 | 9:cbb982b7e353 | 1378 | g_shoot_pressed_flag = false; |
avi23 | 9:cbb982b7e353 | 1379 | |
avi23 | 9:cbb982b7e353 | 1380 | ///Clears the name cursor and moves it |
avi23 | 9:cbb982b7e353 | 1381 | lcd.drawRect(27+(15*name_cursor_pos), 32, 4, 2, 2); |
avi23 | 9:cbb982b7e353 | 1382 | ++name_cursor_pos; |
avi23 | 9:cbb982b7e353 | 1383 | } |
avi23 | 9:cbb982b7e353 | 1384 | |
avi23 | 9:cbb982b7e353 | 1385 | if (g_move_joystick_flag) { |
avi23 | 9:cbb982b7e353 | 1386 | g_move_joystick_flag = false; |
avi23 | 9:cbb982b7e353 | 1387 | |
avi23 | 9:cbb982b7e353 | 1388 | if (joystick.GetYValue() < 0.25f) { |
avi23 | 9:cbb982b7e353 | 1389 | ///Increments the name position, if it is over 25 set it to 0 |
avi23 | 9:cbb982b7e353 | 1390 | if (++name[name_cursor_pos] > 25) { |
avi23 | 9:cbb982b7e353 | 1391 | name[name_cursor_pos] = 0; |
avi23 | 9:cbb982b7e353 | 1392 | } |
avi23 | 9:cbb982b7e353 | 1393 | } else if (joystick.GetYValue() > 0.75f) { |
avi23 | 9:cbb982b7e353 | 1394 | ///Decrements the name position, if it is under 0 set it to 25 |
avi23 | 9:cbb982b7e353 | 1395 | if (--name[name_cursor_pos] < 0) { |
avi23 | 9:cbb982b7e353 | 1396 | name[name_cursor_pos] = 25; |
avi23 | 9:cbb982b7e353 | 1397 | } |
avi23 | 9:cbb982b7e353 | 1398 | } |
avi23 | 9:cbb982b7e353 | 1399 | |
avi23 | 9:cbb982b7e353 | 1400 | lcd.printChar(name[name_cursor_pos] + 65, 27+(15*name_cursor_pos), 3); ///ASCII is offset by 65 |
avi23 | 9:cbb982b7e353 | 1401 | } |
avi23 | 9:cbb982b7e353 | 1402 | |
avi23 | 9:cbb982b7e353 | 1403 | lcd.refresh(); |
avi23 | 9:cbb982b7e353 | 1404 | sleep(); |
avi23 | 9:cbb982b7e353 | 1405 | } |
avi23 | 9:cbb982b7e353 | 1406 | } |
avi23 | 9:cbb982b7e353 | 1407 | |
avi23 | 9:cbb982b7e353 | 1408 | void SaveHighScore(const int (&name)[3]) |
avi23 | 9:cbb982b7e353 | 1409 | { |
avi23 | 9:cbb982b7e353 | 1410 | ///Saves name and score to struct array, overwritting lowest score |
avi23 | 9:cbb982b7e353 | 1411 | for (int letter = 0; letter < 3; ++letter) { |
avi23 | 9:cbb982b7e353 | 1412 | high_scores[2].name[letter] = name[letter] + 65; |
avi23 | 9:cbb982b7e353 | 1413 | } |
avi23 | 9:cbb982b7e353 | 1414 | high_scores[2].score = score; |
avi23 | 9:cbb982b7e353 | 1415 | |
avi23 | 9:cbb982b7e353 | 1416 | ///Sorts struct array |
avi23 | 9:cbb982b7e353 | 1417 | std::sort(high_scores, high_scores + 3, &high_scores_sorter); |
avi23 | 9:cbb982b7e353 | 1418 | |
avi23 | 9:cbb982b7e353 | 1419 | ///Saves the score |
avi23 | 9:cbb982b7e353 | 1420 | std::ofstream high_score_data("/sd/high_scores.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1421 | if (high_score_data.good()) { ///Checks to see if file opening was good |
avi23 | 9:cbb982b7e353 | 1422 | high_score_data.write((char *)(&high_scores), sizeof(high_scores)); |
avi23 | 9:cbb982b7e353 | 1423 | ///Flushes the buffer and saves the file |
avi23 | 9:cbb982b7e353 | 1424 | high_score_data.close(); |
avi23 | 9:cbb982b7e353 | 1425 | lcd.printString("Saved", 27, 4); |
avi23 | 9:cbb982b7e353 | 1426 | } else { |
avi23 | 9:cbb982b7e353 | 1427 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 1428 | lcd.printString("Error", 1, 1); |
avi23 | 9:cbb982b7e353 | 1429 | lcd.printString("Opening", 1, 2); |
avi23 | 9:cbb982b7e353 | 1430 | lcd.printString("File.", 1, 3); |
avi23 | 9:cbb982b7e353 | 1431 | LPWait(2); |
avi23 | 9:cbb982b7e353 | 1432 | } |
avi23 | 9:cbb982b7e353 | 1433 | } |
avi23 | 9:cbb982b7e353 | 1434 | |
avi23 | 9:cbb982b7e353 | 1435 | void SaveGameData() |
avi23 | 9:cbb982b7e353 | 1436 | { |
avi23 | 9:cbb982b7e353 | 1437 | ///Creates the output file as a binary file |
avi23 | 9:cbb982b7e353 | 1438 | std::ofstream save_data("/sd/game_save.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1439 | if (save_data.good()) { ///Checks to see if file opening was good |
avi23 | 9:cbb982b7e353 | 1440 | ///Prints booleans to file |
avi23 | 9:cbb982b7e353 | 1441 | save_data.write((char *)(&invaders_in_state2), sizeof(invaders_in_state2)); |
avi23 | 9:cbb982b7e353 | 1442 | save_data.write((char *)(&invader_direction), sizeof(invader_direction)); |
avi23 | 9:cbb982b7e353 | 1443 | save_data.write((char *)(&cannon_missile_on_screen), sizeof(cannon_missile_on_screen)); |
avi23 | 9:cbb982b7e353 | 1444 | save_data.write((char *)(&ufo_on_screen), sizeof(ufo_on_screen)); |
avi23 | 9:cbb982b7e353 | 1445 | save_data.write((char *)(&ufo_direction), sizeof(ufo_direction)); |
avi23 | 9:cbb982b7e353 | 1446 | save_data.write((char *)(&ufo_bonus), sizeof(ufo_bonus)); |
avi23 | 9:cbb982b7e353 | 1447 | |
avi23 | 9:cbb982b7e353 | 1448 | ///Prints integers to file |
avi23 | 9:cbb982b7e353 | 1449 | save_data.write((char *)(&score), sizeof(score)); |
avi23 | 9:cbb982b7e353 | 1450 | save_data.write((char *)(&shot_count), sizeof(shot_count)); |
avi23 | 9:cbb982b7e353 | 1451 | save_data.write((char *)(&number_of_lives), sizeof(number_of_lives)); |
avi23 | 9:cbb982b7e353 | 1452 | save_data.write((char *)(&cannon_xpos), sizeof(cannon_xpos)); |
avi23 | 9:cbb982b7e353 | 1453 | save_data.write((char *)(&cannon_missile_x_pos), sizeof(cannon_missile_x_pos)); |
avi23 | 9:cbb982b7e353 | 1454 | save_data.write((char *)(&cannon_missile_y_pos), sizeof(cannon_missile_y_pos)); |
avi23 | 9:cbb982b7e353 | 1455 | save_data.write((char *)(&no_of_alive_invaders), sizeof(no_of_alive_invaders)); |
avi23 | 9:cbb982b7e353 | 1456 | save_data.write((char *)(&down_count), sizeof(down_count)); |
avi23 | 9:cbb982b7e353 | 1457 | save_data.write((char *)(&ufo_x_pos), sizeof(ufo_x_pos)); |
avi23 | 9:cbb982b7e353 | 1458 | |
avi23 | 9:cbb982b7e353 | 1459 | ///Prints invaders to file |
avi23 | 9:cbb982b7e353 | 1460 | save_data.write((char *)(&small_invader), sizeof(small_invader)); |
avi23 | 9:cbb982b7e353 | 1461 | save_data.write((char *)(&medium_invader), sizeof(medium_invader)); |
avi23 | 9:cbb982b7e353 | 1462 | save_data.write((char *)(&large_invader), sizeof(large_invader)); |
avi23 | 9:cbb982b7e353 | 1463 | |
avi23 | 9:cbb982b7e353 | 1464 | ///Prints invader missiles and barriers to file |
avi23 | 9:cbb982b7e353 | 1465 | save_data.write((char *)(&invader_normal_missile), sizeof(invader_normal_missile)); |
avi23 | 9:cbb982b7e353 | 1466 | save_data.write((char *)(&barrier), sizeof(barrier)); |
avi23 | 9:cbb982b7e353 | 1467 | |
avi23 | 9:cbb982b7e353 | 1468 | ///Flushes the buffer and saves the file |
avi23 | 9:cbb982b7e353 | 1469 | save_data.close(); |
avi23 | 9:cbb982b7e353 | 1470 | } else { |
avi23 | 9:cbb982b7e353 | 1471 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 1472 | lcd.printString("Error", 1, 1); |
avi23 | 9:cbb982b7e353 | 1473 | lcd.printString("Opening", 1, 2); |
avi23 | 9:cbb982b7e353 | 1474 | lcd.printString("File.", 1, 3); |
avi23 | 9:cbb982b7e353 | 1475 | LPWait(2); |
avi23 | 9:cbb982b7e353 | 1476 | } |
avi23 | 9:cbb982b7e353 | 1477 | |
avi23 | 9:cbb982b7e353 | 1478 | game_state = paused; |
avi23 | 9:cbb982b7e353 | 1479 | } |
avi23 | 9:cbb982b7e353 | 1480 | |
avi23 | 9:cbb982b7e353 | 1481 | void LoadGameData() |
avi23 | 9:cbb982b7e353 | 1482 | { |
avi23 | 9:cbb982b7e353 | 1483 | ///Creates the input binary file object |
avi23 | 9:cbb982b7e353 | 1484 | std::ifstream save_data("/sd/game_save.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1485 | if (save_data.good()) { ///Checks to see if file opening was good |
avi23 | 9:cbb982b7e353 | 1486 | ///Gets booleans from file |
avi23 | 9:cbb982b7e353 | 1487 | save_data.read((char *)(&invaders_in_state2), sizeof(invaders_in_state2)); |
avi23 | 9:cbb982b7e353 | 1488 | save_data.read((char *)(&invader_direction), sizeof(invader_direction)); |
avi23 | 9:cbb982b7e353 | 1489 | save_data.read((char *)(&cannon_missile_on_screen), sizeof(cannon_missile_on_screen)); |
avi23 | 9:cbb982b7e353 | 1490 | save_data.read((char *)(&ufo_on_screen), sizeof(ufo_on_screen)); |
avi23 | 9:cbb982b7e353 | 1491 | save_data.read((char *)(&ufo_direction), sizeof(ufo_direction)); |
avi23 | 9:cbb982b7e353 | 1492 | save_data.read((char *)(&ufo_bonus), sizeof(ufo_bonus)); |
avi23 | 9:cbb982b7e353 | 1493 | |
avi23 | 9:cbb982b7e353 | 1494 | ///Gets integers from file |
avi23 | 9:cbb982b7e353 | 1495 | save_data.read((char *)(&score), sizeof(score)); |
avi23 | 9:cbb982b7e353 | 1496 | save_data.read((char *)(&shot_count), sizeof(shot_count)); |
avi23 | 9:cbb982b7e353 | 1497 | save_data.read((char *)(&number_of_lives), sizeof(number_of_lives)); |
avi23 | 9:cbb982b7e353 | 1498 | save_data.read((char *)(&cannon_xpos), sizeof(cannon_xpos)); |
avi23 | 9:cbb982b7e353 | 1499 | save_data.read((char *)(&cannon_missile_x_pos), sizeof(cannon_missile_x_pos)); |
avi23 | 9:cbb982b7e353 | 1500 | save_data.read((char *)(&cannon_missile_y_pos), sizeof(cannon_missile_y_pos)); |
avi23 | 9:cbb982b7e353 | 1501 | save_data.read((char *)(&no_of_alive_invaders), sizeof(no_of_alive_invaders)); |
avi23 | 9:cbb982b7e353 | 1502 | save_data.read((char *)(&down_count), sizeof(down_count)); |
avi23 | 9:cbb982b7e353 | 1503 | save_data.read((char *)(&ufo_x_pos), sizeof(ufo_x_pos)); |
avi23 | 9:cbb982b7e353 | 1504 | |
avi23 | 9:cbb982b7e353 | 1505 | ///Gets invaders from file |
avi23 | 9:cbb982b7e353 | 1506 | save_data.read((char *)(&small_invader), sizeof(small_invader)); |
avi23 | 9:cbb982b7e353 | 1507 | save_data.read((char *)(&medium_invader), sizeof(medium_invader)); |
avi23 | 9:cbb982b7e353 | 1508 | save_data.read((char *)(&large_invader), sizeof(large_invader)); |
avi23 | 9:cbb982b7e353 | 1509 | |
avi23 | 9:cbb982b7e353 | 1510 | ///Gets invader missiles and barriers from file |
avi23 | 9:cbb982b7e353 | 1511 | save_data.read((char *)(&invader_normal_missile), sizeof(invader_normal_missile)); |
avi23 | 9:cbb982b7e353 | 1512 | save_data.read((char *)(&barrier), sizeof(barrier)); |
avi23 | 9:cbb982b7e353 | 1513 | |
avi23 | 9:cbb982b7e353 | 1514 | ///Closes the file |
avi23 | 9:cbb982b7e353 | 1515 | save_data.close(); |
avi23 | 9:cbb982b7e353 | 1516 | |
avi23 | 9:cbb982b7e353 | 1517 | ///Clears the screen buffer |
avi23 | 9:cbb982b7e353 | 1518 | memset(screen_buffer, 0, sizeof(screen_buffer)); |
avi23 | 9:cbb982b7e353 | 1519 | ///Sets the game state flags |
avi23 | 9:cbb982b7e353 | 1520 | game_state = game; |
avi23 | 9:cbb982b7e353 | 1521 | g_update_screen_flag = true; |
avi23 | 9:cbb982b7e353 | 1522 | g_move_joystick_flag = true; |
avi23 | 9:cbb982b7e353 | 1523 | g_move_enemies_flag = true; |
avi23 | 9:cbb982b7e353 | 1524 | g_fire_buzzer_flag = true; |
avi23 | 9:cbb982b7e353 | 1525 | } else { |
avi23 | 9:cbb982b7e353 | 1526 | lcd.clear(); |
avi23 | 9:cbb982b7e353 | 1527 | lcd.printString("Error", 1, 1); |
avi23 | 9:cbb982b7e353 | 1528 | lcd.printString("Opening", 1, 2); |
avi23 | 9:cbb982b7e353 | 1529 | lcd.printString("File.", 1, 3); |
avi23 | 9:cbb982b7e353 | 1530 | LPWait(2); |
avi23 | 9:cbb982b7e353 | 1531 | game_state = menu; |
avi23 | 9:cbb982b7e353 | 1532 | } |
avi23 | 9:cbb982b7e353 | 1533 | } |
avi23 | 9:cbb982b7e353 | 1534 | |
avi23 | 9:cbb982b7e353 | 1535 | void LoadHighScores() |
avi23 | 9:cbb982b7e353 | 1536 | { |
avi23 | 9:cbb982b7e353 | 1537 | ///Clears high score data before loading file |
avi23 | 9:cbb982b7e353 | 1538 | memset(high_scores, 0, sizeof(high_scores)); |
avi23 | 9:cbb982b7e353 | 1539 | ///Extracts high scores from file |
avi23 | 9:cbb982b7e353 | 1540 | std::ifstream high_score_data("/sd/high_scores.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1541 | if (high_score_data.good()) { |
avi23 | 9:cbb982b7e353 | 1542 | high_score_data.read((char *)(&high_scores), sizeof(high_scores)); |
avi23 | 9:cbb982b7e353 | 1543 | } |
avi23 | 9:cbb982b7e353 | 1544 | high_score_data.close(); |
avi23 | 9:cbb982b7e353 | 1545 | ///If there are any empty names, fill them with AAA to prevent crashes using printString |
avi23 | 9:cbb982b7e353 | 1546 | for (int i = 0; i < 3; ++i) { |
avi23 | 9:cbb982b7e353 | 1547 | if (high_scores[i].name[0] < 'A') { |
avi23 | 9:cbb982b7e353 | 1548 | for (int letter = 0; letter < 3; ++letter) { |
avi23 | 9:cbb982b7e353 | 1549 | high_scores[i].name[letter] = 'A'; |
avi23 | 9:cbb982b7e353 | 1550 | } |
avi23 | 9:cbb982b7e353 | 1551 | } |
avi23 | 9:cbb982b7e353 | 1552 | } |
avi23 | 9:cbb982b7e353 | 1553 | |
avi23 | 9:cbb982b7e353 | 1554 | } |
avi23 | 9:cbb982b7e353 | 1555 | |
avi23 | 9:cbb982b7e353 | 1556 | void SettingsScreen() |
avi23 | 9:cbb982b7e353 | 1557 | { |
avi23 | 9:cbb982b7e353 | 1558 | PrintSettingsText(); |
avi23 | 9:cbb982b7e353 | 1559 | |
avi23 | 9:cbb982b7e353 | 1560 | while (game_state == settings) { |
avi23 | 9:cbb982b7e353 | 1561 | ///Prints options and cursor |
avi23 | 9:cbb982b7e353 | 1562 | PrintSettingsOptions(); |
avi23 | 9:cbb982b7e353 | 1563 | |
avi23 | 9:cbb982b7e353 | 1564 | ///Returns to menu if joystick button is pressed |
avi23 | 9:cbb982b7e353 | 1565 | if (joystick.get_button_flag()) { |
avi23 | 9:cbb982b7e353 | 1566 | joystick.set_button_flag(0); |
avi23 | 9:cbb982b7e353 | 1567 | |
avi23 | 9:cbb982b7e353 | 1568 | game_state = menu; |
avi23 | 9:cbb982b7e353 | 1569 | } |
avi23 | 9:cbb982b7e353 | 1570 | |
avi23 | 9:cbb982b7e353 | 1571 | ///Moves the cursor when the joystick moves |
avi23 | 9:cbb982b7e353 | 1572 | if (g_move_joystick_flag) { |
avi23 | 9:cbb982b7e353 | 1573 | g_move_joystick_flag = false; |
avi23 | 9:cbb982b7e353 | 1574 | |
avi23 | 9:cbb982b7e353 | 1575 | MoveCursor(fsm_settings); |
avi23 | 9:cbb982b7e353 | 1576 | } |
avi23 | 9:cbb982b7e353 | 1577 | |
avi23 | 9:cbb982b7e353 | 1578 | if (g_shoot_pressed_flag) { |
avi23 | 9:cbb982b7e353 | 1579 | g_shoot_pressed_flag = false; |
avi23 | 9:cbb982b7e353 | 1580 | |
avi23 | 9:cbb982b7e353 | 1581 | EditOption(); |
avi23 | 9:cbb982b7e353 | 1582 | } |
avi23 | 9:cbb982b7e353 | 1583 | |
avi23 | 9:cbb982b7e353 | 1584 | lcd.refresh(); |
avi23 | 9:cbb982b7e353 | 1585 | sleep(); |
avi23 | 9:cbb982b7e353 | 1586 | } |
avi23 | 9:cbb982b7e353 | 1587 | } |
avi23 | 9:cbb982b7e353 | 1588 | |
avi23 | 9:cbb982b7e353 | 1589 | void PrintSettingsText() |
avi23 | 9:cbb982b7e353 | 1590 | { |
avi23 | 9:cbb982b7e353 | 1591 | ///Prints the options |
avi23 | 9:cbb982b7e353 | 1592 | lcd.printString("Settings", 17, 0); |
avi23 | 9:cbb982b7e353 | 1593 | lcd.drawLine(0, 7, 83, 7, 2); |
avi23 | 9:cbb982b7e353 | 1594 | lcd.printString("Light:", 0, 2); |
avi23 | 9:cbb982b7e353 | 1595 | lcd.printString("Mute: ", 0, 3); |
avi23 | 9:cbb982b7e353 | 1596 | lcd.printString("Delete Data", 0, 4); |
avi23 | 9:cbb982b7e353 | 1597 | lcd.printString("Back", 10, 5); |
avi23 | 9:cbb982b7e353 | 1598 | } |
avi23 | 9:cbb982b7e353 | 1599 | |
avi23 | 9:cbb982b7e353 | 1600 | void PrintSettingsOptions() |
avi23 | 9:cbb982b7e353 | 1601 | { |
avi23 | 9:cbb982b7e353 | 1602 | ///Prints the active options |
avi23 | 9:cbb982b7e353 | 1603 | char buffer[14] = {0}; |
avi23 | 9:cbb982b7e353 | 1604 | sprintf(buffer, "%d%%", (int)(100*fsm_brightness[brightness_state].output)); |
avi23 | 9:cbb982b7e353 | 1605 | pc.printf("%s\n", buffer); |
avi23 | 9:cbb982b7e353 | 1606 | lcd.printString(buffer, 42, 2); |
avi23 | 9:cbb982b7e353 | 1607 | if (is_muted) { |
avi23 | 9:cbb982b7e353 | 1608 | lcd.printString("On", 42, 3); |
avi23 | 9:cbb982b7e353 | 1609 | } else { |
avi23 | 9:cbb982b7e353 | 1610 | lcd.printString("Off", 42, 3); |
avi23 | 9:cbb982b7e353 | 1611 | } |
avi23 | 9:cbb982b7e353 | 1612 | ///Draws the cursor |
avi23 | 9:cbb982b7e353 | 1613 | 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 |
avi23 | 9:cbb982b7e353 | 1614 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); |
avi23 | 9:cbb982b7e353 | 1615 | } |
avi23 | 9:cbb982b7e353 | 1616 | |
avi23 | 9:cbb982b7e353 | 1617 | void EditOption() |
avi23 | 9:cbb982b7e353 | 1618 | { |
avi23 | 9:cbb982b7e353 | 1619 | if (fsm_state == 0) { ///Change brightness |
avi23 | 9:cbb982b7e353 | 1620 | brightness_state = fsm_brightness[brightness_state].next_state; |
avi23 | 9:cbb982b7e353 | 1621 | lcd.setBrightness(fsm_brightness[brightness_state].output); |
avi23 | 9:cbb982b7e353 | 1622 | ///Clears displayed brightness |
avi23 | 9:cbb982b7e353 | 1623 | lcd.drawRect(42, 16, 24, 7, 2); |
avi23 | 9:cbb982b7e353 | 1624 | } else if (fsm_state == 1) { ///Mute game |
avi23 | 9:cbb982b7e353 | 1625 | is_muted = !is_muted; |
avi23 | 11:eab3fb334bde | 1626 | lcd.drawRect(42, 24, 24, 7, 2); |
avi23 | 9:cbb982b7e353 | 1627 | } else if (fsm_state == 2) { ///Delete save data |
avi23 | 9:cbb982b7e353 | 1628 | DeleteGameData(); |
avi23 | 9:cbb982b7e353 | 1629 | ///Sets FSM list back to 0 and resets the cursor |
avi23 | 9:cbb982b7e353 | 1630 | lcd.drawRect(74, cursor_y_pos, 2, 2, 2); |
avi23 | 9:cbb982b7e353 | 1631 | fsm_state = 0; |
avi23 | 9:cbb982b7e353 | 1632 | } else if (fsm_state == 3) { |
avi23 | 9:cbb982b7e353 | 1633 | game_state = menu; |
avi23 | 9:cbb982b7e353 | 1634 | } |
avi23 | 9:cbb982b7e353 | 1635 | } |
avi23 | 9:cbb982b7e353 | 1636 | |
avi23 | 9:cbb982b7e353 | 1637 | void DeleteGameData() |
avi23 | 9:cbb982b7e353 | 1638 | { |
avi23 | 9:cbb982b7e353 | 1639 | ///Delete game state data |
avi23 | 9:cbb982b7e353 | 1640 | std::ifstream save_data("/sd/game_save.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1641 | if (save_data.good()) { |
avi23 | 9:cbb982b7e353 | 1642 | ///Close the file and remove it |
avi23 | 9:cbb982b7e353 | 1643 | save_data.close(); |
avi23 | 9:cbb982b7e353 | 1644 | remove("/sd/game_save.dat"); |
avi23 | 9:cbb982b7e353 | 1645 | } |
avi23 | 9:cbb982b7e353 | 1646 | ///Deletes high score data |
avi23 | 9:cbb982b7e353 | 1647 | std::ifstream high_scores_data("/sd/high_scores.dat", std::ios::binary); |
avi23 | 9:cbb982b7e353 | 1648 | if (high_scores_data.good()) { |
avi23 | 9:cbb982b7e353 | 1649 | ///Closes the file and remove it |
avi23 | 9:cbb982b7e353 | 1650 | high_scores_data.close(); |
avi23 | 9:cbb982b7e353 | 1651 | remove("/sd/high_scores.dat"); |
avi23 | 9:cbb982b7e353 | 1652 | } |
avi23 | 9:cbb982b7e353 | 1653 | ///Reloads high score list |
avi23 | 9:cbb982b7e353 | 1654 | LoadHighScores(); |
avi23 | 9:cbb982b7e353 | 1655 | } |
avi23 | 9:cbb982b7e353 | 1656 | |
avi23 | 9:cbb982b7e353 | 1657 | void LPWait(float t) |
avi23 | 9:cbb982b7e353 | 1658 | { |
avi23 | 9:cbb982b7e353 | 1659 | ///Sets the wait flag |
avi23 | 9:cbb982b7e353 | 1660 | g_lp_wait_flag = true; |
avi23 | 9:cbb982b7e353 | 1661 | ///Attachs the timeout to fire at the users request then sleep |
avi23 | 9:cbb982b7e353 | 1662 | lp_wait.attach(&lp_wait_isr, t); |
avi23 | 9:cbb982b7e353 | 1663 | while (g_lp_wait_flag) { |
avi23 | 9:cbb982b7e353 | 1664 | sleep(); |
avi23 | 9:cbb982b7e353 | 1665 | } |
avi23 | 9:cbb982b7e353 | 1666 | } |
avi23 | 9:cbb982b7e353 | 1667 | |
avi23 | 9:cbb982b7e353 | 1668 | void SplashScreen() |
avi23 | 9:cbb982b7e353 | 1669 | { |
avi23 | 9:cbb982b7e353 | 1670 | ///Prints text and waits for 3 seconds |
avi23 | 9:cbb982b7e353 | 1671 | lcd.printString("Space Invaders", 0, 1); |
avi23 | 9:cbb982b7e353 | 1672 | lcd.printString("Avinash Patel", 3, 3); |
avi23 | 9:cbb982b7e353 | 1673 | lcd.printString("200860407", 15, 4); |
avi23 | 9:cbb982b7e353 | 1674 | LPWait(3); |
avi23 | 9:cbb982b7e353 | 1675 | } |
avi23 | 9:cbb982b7e353 | 1676 | |
avi23 | 9:cbb982b7e353 | 1677 | void PlayBuzzer() |
avi23 | 9:cbb982b7e353 | 1678 | { |
avi23 | 9:cbb982b7e353 | 1679 | if (play_sound) { |
avi23 | 9:cbb982b7e353 | 1680 | ///Sets the frequency and activates the buzzer |
avi23 | 9:cbb982b7e353 | 1681 | buzzer.period(1/fsm_buzzer[buzzer_state].frequency); |
avi23 | 9:cbb982b7e353 | 1682 | buzzer.write(0.5); |
avi23 | 9:cbb982b7e353 | 1683 | play_sound = false; |
avi23 | 9:cbb982b7e353 | 1684 | } else { |
avi23 | 9:cbb982b7e353 | 1685 | ///Deactivates the buzzer and sets the next frequency |
avi23 | 9:cbb982b7e353 | 1686 | buzzer.write(0); |
avi23 | 9:cbb982b7e353 | 1687 | buzzer_state = fsm_buzzer[buzzer_state].next_state; |
avi23 | 9:cbb982b7e353 | 1688 | play_sound = true; |
avi23 | 9:cbb982b7e353 | 1689 | } |
avi23 | 0:427469992efe | 1690 | } |