Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407

Dependencies:   Joystick N5110 SDFileSystem mbed

Committer:
avi23
Date:
Thu May 05 11:01:17 2016 +0000
Revision:
9:cbb982b7e353
Parent:
8:b2faec20ed8f
Child:
11:eab3fb334bde
Added Splash Screen. Debounce Timeout set to attach on rising edge to button to prevent debounce when button is held and released

Who changed what in which revision?

UserRevisionLine numberNew 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 9:cbb982b7e353 1626 } else if (fsm_state == 2) { ///Delete save data
avi23 9:cbb982b7e353 1627 DeleteGameData();
avi23 9:cbb982b7e353 1628 ///Sets FSM list back to 0 and resets the cursor
avi23 9:cbb982b7e353 1629 lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
avi23 9:cbb982b7e353 1630 fsm_state = 0;
avi23 9:cbb982b7e353 1631 } else if (fsm_state == 3) {
avi23 9:cbb982b7e353 1632 game_state = menu;
avi23 9:cbb982b7e353 1633 }
avi23 9:cbb982b7e353 1634 }
avi23 9:cbb982b7e353 1635
avi23 9:cbb982b7e353 1636 void DeleteGameData()
avi23 9:cbb982b7e353 1637 {
avi23 9:cbb982b7e353 1638 ///Delete game state data
avi23 9:cbb982b7e353 1639 std::ifstream save_data("/sd/game_save.dat", std::ios::binary);
avi23 9:cbb982b7e353 1640 if (save_data.good()) {
avi23 9:cbb982b7e353 1641 ///Close the file and remove it
avi23 9:cbb982b7e353 1642 save_data.close();
avi23 9:cbb982b7e353 1643 remove("/sd/game_save.dat");
avi23 9:cbb982b7e353 1644 }
avi23 9:cbb982b7e353 1645 ///Deletes high score data
avi23 9:cbb982b7e353 1646 std::ifstream high_scores_data("/sd/high_scores.dat", std::ios::binary);
avi23 9:cbb982b7e353 1647 if (high_scores_data.good()) {
avi23 9:cbb982b7e353 1648 ///Closes the file and remove it
avi23 9:cbb982b7e353 1649 high_scores_data.close();
avi23 9:cbb982b7e353 1650 remove("/sd/high_scores.dat");
avi23 9:cbb982b7e353 1651 }
avi23 9:cbb982b7e353 1652 ///Reloads high score list
avi23 9:cbb982b7e353 1653 LoadHighScores();
avi23 9:cbb982b7e353 1654 }
avi23 9:cbb982b7e353 1655
avi23 9:cbb982b7e353 1656 void LPWait(float t)
avi23 9:cbb982b7e353 1657 {
avi23 9:cbb982b7e353 1658 ///Sets the wait flag
avi23 9:cbb982b7e353 1659 g_lp_wait_flag = true;
avi23 9:cbb982b7e353 1660 ///Attachs the timeout to fire at the users request then sleep
avi23 9:cbb982b7e353 1661 lp_wait.attach(&lp_wait_isr, t);
avi23 9:cbb982b7e353 1662 while (g_lp_wait_flag) {
avi23 9:cbb982b7e353 1663 sleep();
avi23 9:cbb982b7e353 1664 }
avi23 9:cbb982b7e353 1665 }
avi23 9:cbb982b7e353 1666
avi23 9:cbb982b7e353 1667 void SplashScreen()
avi23 9:cbb982b7e353 1668 {
avi23 9:cbb982b7e353 1669 ///Prints text and waits for 3 seconds
avi23 9:cbb982b7e353 1670 lcd.printString("Space Invaders", 0, 1);
avi23 9:cbb982b7e353 1671 lcd.printString("Avinash Patel", 3, 3);
avi23 9:cbb982b7e353 1672 lcd.printString("200860407", 15, 4);
avi23 9:cbb982b7e353 1673 LPWait(3);
avi23 9:cbb982b7e353 1674 }
avi23 9:cbb982b7e353 1675
avi23 9:cbb982b7e353 1676 void PlayBuzzer()
avi23 9:cbb982b7e353 1677 {
avi23 9:cbb982b7e353 1678 if (play_sound) {
avi23 9:cbb982b7e353 1679 ///Sets the frequency and activates the buzzer
avi23 9:cbb982b7e353 1680 buzzer.period(1/fsm_buzzer[buzzer_state].frequency);
avi23 9:cbb982b7e353 1681 buzzer.write(0.5);
avi23 9:cbb982b7e353 1682 play_sound = false;
avi23 9:cbb982b7e353 1683 } else {
avi23 9:cbb982b7e353 1684 ///Deactivates the buzzer and sets the next frequency
avi23 9:cbb982b7e353 1685 buzzer.write(0);
avi23 9:cbb982b7e353 1686 buzzer_state = fsm_buzzer[buzzer_state].next_state;
avi23 9:cbb982b7e353 1687 play_sound = true;
avi23 9:cbb982b7e353 1688 }
avi23 0:427469992efe 1689 }