Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407
Dependencies: Joystick N5110 SDFileSystem mbed
main.cpp@8:b2faec20ed8f, 2016-05-03 (annotated)
- Committer:
- avi23
- Date:
- Tue May 03 20:16:06 2016 +0000
- Revision:
- 8:b2faec20ed8f
- Parent:
- 7:babc367a3333
- Child:
- 9:cbb982b7e353
Save game kind of works. Load does not
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 | 8:b2faec20ed8f | 33 | ///Configures the function pointer for the invaders normal missile |
avi23 | 5:34855f712350 | 34 | move_invader_normal_missile_isr[0] = &move_invader_normal_missile_0_isr; |
avi23 | 5:34855f712350 | 35 | move_invader_normal_missile_isr[1] = &move_invader_normal_missile_1_isr; |
avi23 | 0:427469992efe | 36 | |
avi23 | 8:b2faec20ed8f | 37 | ///Samples joystick every 0.05 second |
avi23 | 5:34855f712350 | 38 | move_joystick.attach(&move_joystick_isr, 0.05); |
avi23 | 2:d34c95990605 | 39 | |
avi23 | 2:d34c95990605 | 40 | while (true) { |
avi23 | 8:b2faec20ed8f | 41 | if (game_state == menu) { ///Menu screen |
avi23 | 8:b2faec20ed8f | 42 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 43 | fsm_state = 0; ///Sets the fsm state to 0 |
avi23 | 8:b2faec20ed8f | 44 | MenuScreen(); |
avi23 | 8:b2faec20ed8f | 45 | } else if (game_state == paused) { ///Paused screen |
avi23 | 8:b2faec20ed8f | 46 | ///Clears the screen |
avi23 | 2:d34c95990605 | 47 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 48 | fsm_state = 0; ///Ssets the fsm state to 0 |
avi23 | 8:b2faec20ed8f | 49 | PauseScreen(); |
avi23 | 8:b2faec20ed8f | 50 | } else if (game_state == game) { ///Game screen |
avi23 | 8:b2faec20ed8f | 51 | AttachTickers(); |
avi23 | 8:b2faec20ed8f | 52 | Game(); |
avi23 | 8:b2faec20ed8f | 53 | } else if (game_state == save) { |
avi23 | 8:b2faec20ed8f | 54 | ///Creates file pointer and attaches the file |
avi23 | 8:b2faec20ed8f | 55 | FILE *fp; |
avi23 | 8:b2faec20ed8f | 56 | fp = fopen("/sd/game_save.txt", "w"); |
avi23 | 6:89d4a7f7588b | 57 | |
avi23 | 8:b2faec20ed8f | 58 | if (fp == NULL) { ///If file can't be opened then error |
avi23 | 8:b2faec20ed8f | 59 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 60 | lcd.printString("Error Opening", 1, 1); |
avi23 | 8:b2faec20ed8f | 61 | wait(2.0); |
avi23 | 8:b2faec20ed8f | 62 | } else { |
avi23 | 8:b2faec20ed8f | 63 | ///Prints booleans to file |
avi23 | 8:b2faec20ed8f | 64 | fprintf(fp, "%d\n", invaders_in_state2); |
avi23 | 8:b2faec20ed8f | 65 | fprintf(fp, "%d,%d,%d,%d,%d,%d\n", invader_direction, cannon_missile_on_screen, ufo_on_screen, ufo_direction, ufo_bonus, is_muted); |
avi23 | 8:b2faec20ed8f | 66 | ///Prints integers to file |
avi23 | 8:b2faec20ed8f | 67 | fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", score, shot_count, number_of_lives, cannon_xpos, cannon_missile_x_pos, cannon_missile_y_pos, no_of_alive_invaders, down_count, ufo_x_pos); |
avi23 | 8:b2faec20ed8f | 68 | ///Prints small invader info to file |
avi23 | 8:b2faec20ed8f | 69 | for (int small = 0; small < 5; ++small) { |
avi23 | 8:b2faec20ed8f | 70 | fprintf(fp, "%d,%d,%d\n", small_invader[small].x_pos, small_invader[small].y_pos, small_invader[small].status); |
avi23 | 8:b2faec20ed8f | 71 | } |
avi23 | 8:b2faec20ed8f | 72 | ///Prints medium invader info to file |
avi23 | 8:b2faec20ed8f | 73 | for (int medium = 0; medium < 5; ++medium) { |
avi23 | 8:b2faec20ed8f | 74 | fprintf(fp, "%d,%d,%d\n", medium_invader[medium].x_pos, medium_invader[medium].y_pos, medium_invader[medium].status); |
avi23 | 8:b2faec20ed8f | 75 | } |
avi23 | 8:b2faec20ed8f | 76 | ///Prints large invader info to file |
avi23 | 8:b2faec20ed8f | 77 | for (int large = 0; large < 5; ++large) { |
avi23 | 8:b2faec20ed8f | 78 | fprintf(fp, "%d,%d,%d\n", large_invader[large].x_pos, large_invader[large].y_pos, large_invader[large].status); |
avi23 | 6:89d4a7f7588b | 79 | } |
avi23 | 8:b2faec20ed8f | 80 | ///Stores invader missile data |
avi23 | 8:b2faec20ed8f | 81 | for (int missile = 0; missile < 2; ++missile) { |
avi23 | 8:b2faec20ed8f | 82 | fprintf(fp, "%d,%d,%d\n", invader_normal_missile[missile].x_pos, invader_normal_missile[missile].y_pos, invader_normal_missile[missile].fired); |
avi23 | 8:b2faec20ed8f | 83 | } |
avi23 | 8:b2faec20ed8f | 84 | ///Stores barrier data |
avi23 | 8:b2faec20ed8f | 85 | for (int barrier_no = 0; barrier_no < 3; ++barrier_no) { |
avi23 | 8:b2faec20ed8f | 86 | fprintf(fp, "%d,%d\n", barrier[barrier_no].x_pos, barrier[barrier_no].y_pos); |
avi23 | 8:b2faec20ed8f | 87 | ///Stores barrier before bitmaps |
avi23 | 8:b2faec20ed8f | 88 | for (int row = 0; row < 8; ++row) { |
avi23 | 8:b2faec20ed8f | 89 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 90 | if (col < 13) { |
avi23 | 8:b2faec20ed8f | 91 | fprintf(fp, "%d,", barrier[barrier_no].before_bitmap[row][col]); |
avi23 | 8:b2faec20ed8f | 92 | } else { |
avi23 | 8:b2faec20ed8f | 93 | fprintf(fp, "%d\n", barrier[barrier_no].before_bitmap[row][col]); |
avi23 | 8:b2faec20ed8f | 94 | } |
avi23 | 8:b2faec20ed8f | 95 | } |
avi23 | 8:b2faec20ed8f | 96 | } |
avi23 | 8:b2faec20ed8f | 97 | ///Stores barrier after bitmaps |
avi23 | 8:b2faec20ed8f | 98 | for (int row = 0; row < 8; ++row) { |
avi23 | 8:b2faec20ed8f | 99 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 100 | if (col < 13) { |
avi23 | 8:b2faec20ed8f | 101 | fprintf(fp, "%d,", barrier[barrier_no].after_bitmap[row][col]); |
avi23 | 8:b2faec20ed8f | 102 | } else { |
avi23 | 8:b2faec20ed8f | 103 | fprintf(fp, "%d\n", barrier[barrier_no].after_bitmap[row][col]); |
avi23 | 8:b2faec20ed8f | 104 | } |
avi23 | 8:b2faec20ed8f | 105 | } |
avi23 | 6:89d4a7f7588b | 106 | } |
avi23 | 6:89d4a7f7588b | 107 | } |
avi23 | 5:34855f712350 | 108 | |
avi23 | 8:b2faec20ed8f | 109 | fclose(fp); |
avi23 | 8:b2faec20ed8f | 110 | game_state = paused; |
avi23 | 1:b300d052d549 | 111 | } |
avi23 | 8:b2faec20ed8f | 112 | } else if (game_state == load) { |
avi23 | 8:b2faec20ed8f | 113 | ///Creates file pointer and attaches the file |
avi23 | 8:b2faec20ed8f | 114 | FILE *fp; |
avi23 | 8:b2faec20ed8f | 115 | fp = fopen("/sd/game_save.txt", "r"); |
avi23 | 8:b2faec20ed8f | 116 | rewind(fp); |
avi23 | 8:b2faec20ed8f | 117 | |
avi23 | 8:b2faec20ed8f | 118 | if (fp == NULL) { ///If file can't be opened then error |
avi23 | 8:b2faec20ed8f | 119 | lcd.clear(); |
avi23 | 8:b2faec20ed8f | 120 | lcd.printString("Error Opening", 1, 1); |
avi23 | 8:b2faec20ed8f | 121 | wait(2.0); |
avi23 | 8:b2faec20ed8f | 122 | |
avi23 | 8:b2faec20ed8f | 123 | game_state = menu; |
avi23 | 8:b2faec20ed8f | 124 | } else { |
avi23 | 8:b2faec20ed8f | 125 | int test; |
avi23 | 8:b2faec20ed8f | 126 | ///Prints booleans to file |
avi23 | 8:b2faec20ed8f | 127 | fscanf(fp, "%d\n", &invaders_in_state2); |
avi23 | 8:b2faec20ed8f | 128 | test = fscanf(fp, "%d,%d,%d,%d,%d,%d", &invader_direction, &cannon_missile_on_screen, &ufo_on_screen, &ufo_direction, &ufo_bonus, &is_muted); |
avi23 | 8:b2faec20ed8f | 129 | |
avi23 | 8:b2faec20ed8f | 130 | pc.printf("Bool: %d\n", test); |
avi23 | 8:b2faec20ed8f | 131 | ///Prints integers to file |
avi23 | 8:b2faec20ed8f | 132 | test = fscanf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,%d", &score, &shot_count, &number_of_lives, &cannon_xpos, &cannon_missile_x_pos, &cannon_missile_y_pos, &no_of_alive_invaders, &down_count, &ufo_x_pos); |
avi23 | 8:b2faec20ed8f | 133 | pc.printf("Int: %d\n", test); |
avi23 | 8:b2faec20ed8f | 134 | ///Prints small invader info to file |
avi23 | 8:b2faec20ed8f | 135 | for (int small = 0; small < 5; ++small) { |
avi23 | 8:b2faec20ed8f | 136 | test = fscanf(fp, "%d,%d,%d", &(small_invader[small].x_pos), &(small_invader[small].y_pos), &(small_invader[small].status)); |
avi23 | 8:b2faec20ed8f | 137 | pc.printf("Small: %d\n", test); |
avi23 | 8:b2faec20ed8f | 138 | } |
avi23 | 8:b2faec20ed8f | 139 | ///Prints medium invader info to file |
avi23 | 8:b2faec20ed8f | 140 | for (int medium = 0; medium < 5; ++medium) { |
avi23 | 8:b2faec20ed8f | 141 | test = fscanf(fp, "%d,%d,%d", &(medium_invader[medium].x_pos), &(medium_invader[medium].y_pos), &(medium_invader[medium].status)); |
avi23 | 8:b2faec20ed8f | 142 | pc.printf("Medium: %d\n", test); |
avi23 | 8:b2faec20ed8f | 143 | } |
avi23 | 8:b2faec20ed8f | 144 | ///Prints large invader info to file |
avi23 | 8:b2faec20ed8f | 145 | for (int large = 0; large < 5; ++large) { |
avi23 | 8:b2faec20ed8f | 146 | test = fscanf(fp, "%d,%d,%d", &(large_invader[large].x_pos), &(large_invader[large].y_pos), &(large_invader[large].status)); |
avi23 | 8:b2faec20ed8f | 147 | pc.printf("Large: %d\n", test); |
avi23 | 8:b2faec20ed8f | 148 | } |
avi23 | 8:b2faec20ed8f | 149 | ///Stores invader missile data |
avi23 | 8:b2faec20ed8f | 150 | for (int missile = 0; missile < 2; ++missile) { |
avi23 | 8:b2faec20ed8f | 151 | test = fscanf(fp, "%d,%d,%d", &(invader_normal_missile[missile].x_pos), &(invader_normal_missile[missile].y_pos), &(invader_normal_missile[missile].fired)); |
avi23 | 8:b2faec20ed8f | 152 | pc.printf("Missile: %d\n", test); |
avi23 | 8:b2faec20ed8f | 153 | } |
avi23 | 8:b2faec20ed8f | 154 | ///Stores barrier data |
avi23 | 8:b2faec20ed8f | 155 | for (int barrier_no = 0; barrier_no < 3; ++barrier_no) { |
avi23 | 8:b2faec20ed8f | 156 | test = fscanf(fp, "%d,%d", &(barrier[barrier_no].x_pos), &(barrier[barrier_no].y_pos)); |
avi23 | 8:b2faec20ed8f | 157 | pc.printf("Barrier: %d\n", test); |
avi23 | 8:b2faec20ed8f | 158 | ///Stores barrier before bitmaps |
avi23 | 8:b2faec20ed8f | 159 | for (int row = 0; row < 8; ++row) { |
avi23 | 8:b2faec20ed8f | 160 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 161 | if (col < 13) { |
avi23 | 8:b2faec20ed8f | 162 | test = fscanf(fp, "%d,", &(barrier[barrier_no].before_bitmap[row][col])); |
avi23 | 8:b2faec20ed8f | 163 | pc.printf("Barrier Before: %d\n", test); |
avi23 | 8:b2faec20ed8f | 164 | } else { |
avi23 | 8:b2faec20ed8f | 165 | test = fscanf(fp, "%d", &(barrier[barrier_no].before_bitmap[row][col])); |
avi23 | 8:b2faec20ed8f | 166 | pc.printf("Barrier Before: %d\n", test); |
avi23 | 8:b2faec20ed8f | 167 | } |
avi23 | 8:b2faec20ed8f | 168 | } |
avi23 | 8:b2faec20ed8f | 169 | } |
avi23 | 8:b2faec20ed8f | 170 | ///Stores barrier after bitmaps |
avi23 | 8:b2faec20ed8f | 171 | for (int row = 0; row < 8; ++row) { |
avi23 | 8:b2faec20ed8f | 172 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 173 | if (col < 13) { |
avi23 | 8:b2faec20ed8f | 174 | test = fscanf(fp, "%d,", &(barrier[barrier_no].after_bitmap[row][col])); |
avi23 | 8:b2faec20ed8f | 175 | pc.printf("Barrier After: %d\n", test); |
avi23 | 8:b2faec20ed8f | 176 | } else { |
avi23 | 8:b2faec20ed8f | 177 | test = fscanf(fp, "%d", &(barrier[barrier_no].after_bitmap[row][col])); |
avi23 | 8:b2faec20ed8f | 178 | pc.printf("Barrier After: %d\n", test); |
avi23 | 8:b2faec20ed8f | 179 | } |
avi23 | 8:b2faec20ed8f | 180 | } |
avi23 | 8:b2faec20ed8f | 181 | } |
avi23 | 8:b2faec20ed8f | 182 | } |
avi23 | 8:b2faec20ed8f | 183 | |
avi23 | 8:b2faec20ed8f | 184 | |
avi23 | 8:b2faec20ed8f | 185 | fclose(fp); |
avi23 | 8:b2faec20ed8f | 186 | game_state = game; |
avi23 | 8:b2faec20ed8f | 187 | |
avi23 | 8:b2faec20ed8f | 188 | g_update_screen_flag = true; |
avi23 | 8:b2faec20ed8f | 189 | g_move_joystick_flag = true; |
avi23 | 8:b2faec20ed8f | 190 | g_move_enemies_flag = true; |
avi23 | 8:b2faec20ed8f | 191 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 192 | } |
avi23 | 0:427469992efe | 193 | } |
avi23 | 2:d34c95990605 | 194 | |
avi23 | 0:427469992efe | 195 | sleep(); |
avi23 | 0:427469992efe | 196 | } |
avi23 | 0:427469992efe | 197 | } |
avi23 | 0:427469992efe | 198 | |
avi23 | 0:427469992efe | 199 | void init_K64F() |
avi23 | 0:427469992efe | 200 | { |
avi23 | 8:b2faec20ed8f | 201 | /// on-board LEDs are active-low, so set pin high to turn them off. |
avi23 | 0:427469992efe | 202 | r_led = 1; |
avi23 | 0:427469992efe | 203 | g_led = 1; |
avi23 | 0:427469992efe | 204 | b_led = 1; |
avi23 | 0:427469992efe | 205 | |
avi23 | 8:b2faec20ed8f | 206 | /// since the on-board switches have external pull-ups, we should disable the internal pull-down |
avi23 | 8:b2faec20ed8f | 207 | /// resistors that are enabled by default using InterruptIn |
avi23 | 0:427469992efe | 208 | sw2.mode(PullNone); |
avi23 | 0:427469992efe | 209 | sw3.mode(PullNone); |
avi23 | 0:427469992efe | 210 | } |
avi23 | 0:427469992efe | 211 | |
avi23 | 0:427469992efe | 212 | void error() |
avi23 | 0:427469992efe | 213 | { |
avi23 | 8:b2faec20ed8f | 214 | while(1) { /// if error, hang while flashing error message |
avi23 | 0:427469992efe | 215 | r_led = 0; |
avi23 | 0:427469992efe | 216 | wait(0.2); |
avi23 | 0:427469992efe | 217 | r_led = 1; |
avi23 | 0:427469992efe | 218 | wait(0.2); |
avi23 | 0:427469992efe | 219 | } |
avi23 | 0:427469992efe | 220 | } |
avi23 | 0:427469992efe | 221 | |
avi23 | 0:427469992efe | 222 | void init_serial() |
avi23 | 0:427469992efe | 223 | { |
avi23 | 8:b2faec20ed8f | 224 | /// set to highest baud - ensure terminal software matches |
avi23 | 0:427469992efe | 225 | pc.baud(115200); |
avi23 | 0:427469992efe | 226 | } |
avi23 | 0:427469992efe | 227 | |
avi23 | 8:b2faec20ed8f | 228 | ///Seeds the random number generator with noise from an analog in pin |
avi23 | 5:34855f712350 | 229 | void init_rng() |
avi23 | 5:34855f712350 | 230 | { |
avi23 | 8:b2faec20ed8f | 231 | AnalogIn rng_seed(PTC10); ///Creates a AnalogIn on a unused pin |
avi23 | 8:b2faec20ed8f | 232 | srand(floor(10000*rng_seed.read())); ///Sets the seed as 10000x the input of the analog in |
avi23 | 5:34855f712350 | 233 | } |
avi23 | 5:34855f712350 | 234 | |
avi23 | 2:d34c95990605 | 235 | void init_shoot() |
avi23 | 0:427469992efe | 236 | { |
avi23 | 2:d34c95990605 | 237 | shoot_button.mode(PullUp); |
avi23 | 2:d34c95990605 | 238 | shoot_button.fall(&shoot_pressed_isr); |
avi23 | 2:d34c95990605 | 239 | } |
avi23 | 2:d34c95990605 | 240 | |
avi23 | 2:d34c95990605 | 241 | void update_screen_isr() |
avi23 | 2:d34c95990605 | 242 | { |
avi23 | 2:d34c95990605 | 243 | g_update_screen_flag = true; |
avi23 | 0:427469992efe | 244 | } |
avi23 | 0:427469992efe | 245 | |
avi23 | 5:34855f712350 | 246 | void move_enemies_isr() |
avi23 | 5:34855f712350 | 247 | { |
avi23 | 5:34855f712350 | 248 | g_move_enemies_flag = true; |
avi23 | 5:34855f712350 | 249 | } |
avi23 | 5:34855f712350 | 250 | |
avi23 | 2:d34c95990605 | 251 | void shoot_pressed_isr() |
avi23 | 2:d34c95990605 | 252 | { |
avi23 | 8:b2faec20ed8f | 253 | ///Only sets the shoot pressed flag 0.1s after the last press |
avi23 | 6:89d4a7f7588b | 254 | if (!g_shoot_button_debounce_flag) { |
avi23 | 6:89d4a7f7588b | 255 | g_shoot_pressed_flag = true; |
avi23 | 6:89d4a7f7588b | 256 | g_shoot_button_debounce_flag = true; |
avi23 | 6:89d4a7f7588b | 257 | |
avi23 | 8:b2faec20ed8f | 258 | ///Attaches a timeout to clear the debounce flag 0.125 seconds after it was set |
avi23 | 6:89d4a7f7588b | 259 | shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125); |
avi23 | 6:89d4a7f7588b | 260 | } |
avi23 | 5:34855f712350 | 261 | } |
avi23 | 5:34855f712350 | 262 | |
avi23 | 5:34855f712350 | 263 | void move_cannon_missile_isr() |
avi23 | 5:34855f712350 | 264 | { |
avi23 | 5:34855f712350 | 265 | g_move_cannon_missile_flag = true; |
avi23 | 5:34855f712350 | 266 | } |
avi23 | 5:34855f712350 | 267 | |
avi23 | 5:34855f712350 | 268 | void move_joystick_isr() |
avi23 | 5:34855f712350 | 269 | { |
avi23 | 8:b2faec20ed8f | 270 | ///Always set the move flag in a game |
avi23 | 5:34855f712350 | 271 | if (game_state == game) { |
avi23 | 5:34855f712350 | 272 | g_move_joystick_flag = true; |
avi23 | 5:34855f712350 | 273 | } else if (!g_joystick_cursor_regulator_flag) { |
avi23 | 8:b2faec20ed8f | 274 | ///Only sets the flag if the regulator is not set |
avi23 | 5:34855f712350 | 275 | g_move_joystick_flag = true; |
avi23 | 5:34855f712350 | 276 | g_joystick_cursor_regulator_flag = true; |
avi23 | 5:34855f712350 | 277 | |
avi23 | 8:b2faec20ed8f | 278 | ///Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically |
avi23 | 6:89d4a7f7588b | 279 | joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.1); |
avi23 | 5:34855f712350 | 280 | } |
avi23 | 5:34855f712350 | 281 | } |
avi23 | 5:34855f712350 | 282 | |
avi23 | 6:89d4a7f7588b | 283 | void joystick_cursor_regulator_isr() |
avi23 | 6:89d4a7f7588b | 284 | { |
avi23 | 5:34855f712350 | 285 | g_joystick_cursor_regulator_flag = false; |
avi23 | 5:34855f712350 | 286 | } |
avi23 | 5:34855f712350 | 287 | |
avi23 | 6:89d4a7f7588b | 288 | void shoot_button_debounce_isr() |
avi23 | 6:89d4a7f7588b | 289 | { |
avi23 | 6:89d4a7f7588b | 290 | g_shoot_button_debounce_flag = false; |
avi23 | 6:89d4a7f7588b | 291 | } |
avi23 | 6:89d4a7f7588b | 292 | |
avi23 | 5:34855f712350 | 293 | void move_invader_normal_missile_0_isr() |
avi23 | 5:34855f712350 | 294 | { |
avi23 | 5:34855f712350 | 295 | g_move_invader_normal_missile_flag[0] = true; |
avi23 | 5:34855f712350 | 296 | } |
avi23 | 5:34855f712350 | 297 | |
avi23 | 5:34855f712350 | 298 | void move_invader_normal_missile_1_isr() |
avi23 | 5:34855f712350 | 299 | { |
avi23 | 5:34855f712350 | 300 | g_move_invader_normal_missile_flag[1] = true; |
avi23 | 5:34855f712350 | 301 | } |
avi23 | 5:34855f712350 | 302 | |
avi23 | 5:34855f712350 | 303 | void cannon_hit_isr() |
avi23 | 5:34855f712350 | 304 | { |
avi23 | 5:34855f712350 | 305 | g_cannon_hit_flag = false; |
avi23 | 2:d34c95990605 | 306 | } |
avi23 | 2:d34c95990605 | 307 | |
avi23 | 8:b2faec20ed8f | 308 | void move_ufo_isr() |
avi23 | 8:b2faec20ed8f | 309 | { |
avi23 | 8:b2faec20ed8f | 310 | g_move_ufo_flag = true; |
avi23 | 8:b2faec20ed8f | 311 | } |
avi23 | 8:b2faec20ed8f | 312 | |
avi23 | 8:b2faec20ed8f | 313 | void fire_buzzer_isr() |
avi23 | 8:b2faec20ed8f | 314 | { |
avi23 | 8:b2faec20ed8f | 315 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 316 | } |
avi23 | 8:b2faec20ed8f | 317 | |
avi23 | 5:34855f712350 | 318 | void Game() |
avi23 | 6:89d4a7f7588b | 319 | { |
avi23 | 8:b2faec20ed8f | 320 | ///Stays within the loop while the selected state is game |
avi23 | 5:34855f712350 | 321 | while (game_state == game) { |
avi23 | 8:b2faec20ed8f | 322 | pc.printf("Mute: %d\n", is_muted); |
avi23 | 8:b2faec20ed8f | 323 | ///If the game is over detach all the tickers |
avi23 | 5:34855f712350 | 324 | if (number_of_lives == 0) { |
avi23 | 5:34855f712350 | 325 | DetachTickers(); |
avi23 | 5:34855f712350 | 326 | |
avi23 | 5:34855f712350 | 327 | lcd.clear(); |
avi23 | 5:34855f712350 | 328 | lcd.printString("Game Over.", 1, 2); |
avi23 | 7:babc367a3333 | 329 | char buffer[14]; |
avi23 | 7:babc367a3333 | 330 | sprintf(buffer, "Score: %d", score); |
avi23 | 7:babc367a3333 | 331 | lcd.printString(buffer, 1, 3); |
avi23 | 8:b2faec20ed8f | 332 | } else if (no_of_alive_invaders == 0) { ///If the player wins a round |
avi23 | 8:b2faec20ed8f | 333 | ///Resets the no of alive invaders |
avi23 | 5:34855f712350 | 334 | no_of_alive_invaders = 15; |
avi23 | 8:b2faec20ed8f | 335 | down_count = 0; |
avi23 | 8:b2faec20ed8f | 336 | ///Detaches the enemy ticker while reinitalising invaders |
avi23 | 5:34855f712350 | 337 | move_enemies.detach(); |
avi23 | 8:b2faec20ed8f | 338 | ///Reinitalises objects |
avi23 | 5:34855f712350 | 339 | InitSmallInvaders(); |
avi23 | 5:34855f712350 | 340 | InitMediumInvaders(); |
avi23 | 5:34855f712350 | 341 | InitLargeInvaders(); |
avi23 | 8:b2faec20ed8f | 342 | ///Reattaches enemy ticker |
avi23 | 5:34855f712350 | 343 | move_enemies.attach(&move_enemies_isr, 1); |
avi23 | 5:34855f712350 | 344 | } else { |
avi23 | 8:b2faec20ed8f | 345 | ///Updates pixels on the screen |
avi23 | 5:34855f712350 | 346 | if (g_update_screen_flag) { |
avi23 | 5:34855f712350 | 347 | g_update_screen_flag = false; |
avi23 | 5:34855f712350 | 348 | |
avi23 | 5:34855f712350 | 349 | UpdateScreen(); |
avi23 | 5:34855f712350 | 350 | } |
avi23 | 5:34855f712350 | 351 | |
avi23 | 8:b2faec20ed8f | 352 | ///Controls cannon movement |
avi23 | 5:34855f712350 | 353 | if (g_move_joystick_flag) { |
avi23 | 5:34855f712350 | 354 | g_move_joystick_flag = false; |
avi23 | 5:34855f712350 | 355 | |
avi23 | 5:34855f712350 | 356 | MoveCannon(); |
avi23 | 5:34855f712350 | 357 | DrawBarriers(); |
avi23 | 5:34855f712350 | 358 | } |
avi23 | 5:34855f712350 | 359 | |
avi23 | 8:b2faec20ed8f | 360 | ///Controls enemy movement |
avi23 | 5:34855f712350 | 361 | if (g_move_enemies_flag) { |
avi23 | 5:34855f712350 | 362 | g_move_enemies_flag = false; |
avi23 | 5:34855f712350 | 363 | |
avi23 | 8:b2faec20ed8f | 364 | ///Increses the speed the invaders move |
avi23 | 5:34855f712350 | 365 | move_enemies.detach(); |
avi23 | 5:34855f712350 | 366 | ticker_period = 0.1+(no_of_alive_invaders*0.06); |
avi23 | 5:34855f712350 | 367 | move_enemies.attach(&move_enemies_isr, ticker_period); |
avi23 | 5:34855f712350 | 368 | |
avi23 | 8:b2faec20ed8f | 369 | //Attach the buzzer timeout if mute is unselected |
avi23 | 8:b2faec20ed8f | 370 | if (!is_muted) { |
avi23 | 8:b2faec20ed8f | 371 | fire_buzzer.attach(&fire_buzzer_isr, ticker_period/2.0f); |
avi23 | 8:b2faec20ed8f | 372 | } |
avi23 | 8:b2faec20ed8f | 373 | |
avi23 | 8:b2faec20ed8f | 374 | ///Clears the old bitmaps |
avi23 | 5:34855f712350 | 375 | ClearSmallInvaders(); |
avi23 | 5:34855f712350 | 376 | ClearMediumInvaders(); |
avi23 | 5:34855f712350 | 377 | ClearLargeInvaders(); |
avi23 | 5:34855f712350 | 378 | |
avi23 | 5:34855f712350 | 379 | MoveInvaderXPositions(); |
avi23 | 8:b2faec20ed8f | 380 | ///Switches the bitmap state |
avi23 | 5:34855f712350 | 381 | invaders_in_state2 = !invaders_in_state2; |
avi23 | 5:34855f712350 | 382 | |
avi23 | 8:b2faec20ed8f | 383 | ///Draws the invaders |
avi23 | 5:34855f712350 | 384 | DrawSmallInvaders(); |
avi23 | 5:34855f712350 | 385 | DrawMediumInvaders(); |
avi23 | 5:34855f712350 | 386 | DrawLargeInvaders(); |
avi23 | 5:34855f712350 | 387 | |
avi23 | 8:b2faec20ed8f | 388 | ///Attempts to fire the invaders missiles |
avi23 | 5:34855f712350 | 389 | AttemptToFireInvaderNormalMissiles(); |
avi23 | 8:b2faec20ed8f | 390 | |
avi23 | 8:b2faec20ed8f | 391 | ///Attempts to spawn UFO |
avi23 | 8:b2faec20ed8f | 392 | AttemptToSpawnUFO(); |
avi23 | 5:34855f712350 | 393 | } |
avi23 | 5:34855f712350 | 394 | |
avi23 | 8:b2faec20ed8f | 395 | if (g_fire_buzzer_flag && !is_muted) { |
avi23 | 8:b2faec20ed8f | 396 | g_fire_buzzer_flag = false; |
avi23 | 8:b2faec20ed8f | 397 | |
avi23 | 8:b2faec20ed8f | 398 | if (play_sound) { |
avi23 | 8:b2faec20ed8f | 399 | buzzer.period(1/fsm_buzzer[buzzer_state].frequency); |
avi23 | 8:b2faec20ed8f | 400 | buzzer.write(0.5); |
avi23 | 8:b2faec20ed8f | 401 | play_sound = false; |
avi23 | 8:b2faec20ed8f | 402 | } else { |
avi23 | 8:b2faec20ed8f | 403 | buzzer.write(0); |
avi23 | 8:b2faec20ed8f | 404 | buzzer_state = fsm_buzzer[buzzer_state].next_state; |
avi23 | 8:b2faec20ed8f | 405 | play_sound = true; |
avi23 | 8:b2faec20ed8f | 406 | } |
avi23 | 8:b2faec20ed8f | 407 | } |
avi23 | 8:b2faec20ed8f | 408 | |
avi23 | 8:b2faec20ed8f | 409 | ///Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen |
avi23 | 5:34855f712350 | 410 | if (g_shoot_pressed_flag) { |
avi23 | 5:34855f712350 | 411 | g_shoot_pressed_flag = false; |
avi23 | 5:34855f712350 | 412 | |
avi23 | 5:34855f712350 | 413 | if (!cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 414 | FireCannonMissile(); |
avi23 | 8:b2faec20ed8f | 415 | |
avi23 | 8:b2faec20ed8f | 416 | ///Counts fired missiles to see if the ufo bonus can be applied |
avi23 | 8:b2faec20ed8f | 417 | if (ufo_bonus && shot_count > 14) { |
avi23 | 8:b2faec20ed8f | 418 | shot_count = 0; |
avi23 | 8:b2faec20ed8f | 419 | } else if (shot_count > 22) { |
avi23 | 8:b2faec20ed8f | 420 | shot_count = 0; |
avi23 | 8:b2faec20ed8f | 421 | } else { |
avi23 | 8:b2faec20ed8f | 422 | ++shot_count; |
avi23 | 8:b2faec20ed8f | 423 | } |
avi23 | 5:34855f712350 | 424 | } |
avi23 | 5:34855f712350 | 425 | } |
avi23 | 5:34855f712350 | 426 | |
avi23 | 8:b2faec20ed8f | 427 | ///Move the cannon shot |
avi23 | 5:34855f712350 | 428 | if (g_move_cannon_missile_flag) { |
avi23 | 5:34855f712350 | 429 | g_move_cannon_missile_flag = false; |
avi23 | 5:34855f712350 | 430 | |
avi23 | 5:34855f712350 | 431 | MoveCannonMissile(); |
avi23 | 5:34855f712350 | 432 | } |
avi23 | 5:34855f712350 | 433 | |
avi23 | 8:b2faec20ed8f | 434 | ///Moves the invaders 1st normal missile |
avi23 | 5:34855f712350 | 435 | if (g_move_invader_normal_missile_flag[0]) { |
avi23 | 5:34855f712350 | 436 | g_move_invader_normal_missile_flag[0] = false; |
avi23 | 5:34855f712350 | 437 | |
avi23 | 5:34855f712350 | 438 | MoveInvaderNormalMissile(0); |
avi23 | 5:34855f712350 | 439 | } |
avi23 | 5:34855f712350 | 440 | |
avi23 | 8:b2faec20ed8f | 441 | ///Moves the invaders 2nd normal missile |
avi23 | 5:34855f712350 | 442 | if (g_move_invader_normal_missile_flag[1]) { |
avi23 | 5:34855f712350 | 443 | g_move_invader_normal_missile_flag[1] = false; |
avi23 | 5:34855f712350 | 444 | |
avi23 | 5:34855f712350 | 445 | MoveInvaderNormalMissile(1); |
avi23 | 5:34855f712350 | 446 | } |
avi23 | 5:34855f712350 | 447 | |
avi23 | 8:b2faec20ed8f | 448 | ///Moves the UFO |
avi23 | 8:b2faec20ed8f | 449 | if (g_move_ufo_flag) { |
avi23 | 8:b2faec20ed8f | 450 | g_move_ufo_flag = false; |
avi23 | 8:b2faec20ed8f | 451 | |
avi23 | 8:b2faec20ed8f | 452 | ///Clears the UFO |
avi23 | 8:b2faec20ed8f | 453 | ClearUFO(); |
avi23 | 8:b2faec20ed8f | 454 | |
avi23 | 8:b2faec20ed8f | 455 | ///Moves the UFO in the correct direction |
avi23 | 8:b2faec20ed8f | 456 | if (ufo_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 457 | ufo_x_pos += 2; |
avi23 | 8:b2faec20ed8f | 458 | } else { |
avi23 | 8:b2faec20ed8f | 459 | ufo_x_pos -= 2; |
avi23 | 8:b2faec20ed8f | 460 | } |
avi23 | 8:b2faec20ed8f | 461 | |
avi23 | 8:b2faec20ed8f | 462 | ///Draws the UFO |
avi23 | 8:b2faec20ed8f | 463 | DrawUFO(); |
avi23 | 8:b2faec20ed8f | 464 | } |
avi23 | 8:b2faec20ed8f | 465 | |
avi23 | 5:34855f712350 | 466 | if (joystick.get_button_flag()) { |
avi23 | 5:34855f712350 | 467 | joystick.set_button_flag(0); |
avi23 | 5:34855f712350 | 468 | |
avi23 | 8:b2faec20ed8f | 469 | ///Detach all game tickers |
avi23 | 5:34855f712350 | 470 | DetachTickers(); |
avi23 | 5:34855f712350 | 471 | game_state = paused; |
avi23 | 5:34855f712350 | 472 | } |
avi23 | 5:34855f712350 | 473 | } |
avi23 | 5:34855f712350 | 474 | |
avi23 | 5:34855f712350 | 475 | sleep(); |
avi23 | 5:34855f712350 | 476 | } |
avi23 | 2:d34c95990605 | 477 | } |
avi23 | 2:d34c95990605 | 478 | |
avi23 | 7:babc367a3333 | 479 | void InitaliseGame() |
avi23 | 7:babc367a3333 | 480 | { |
avi23 | 8:b2faec20ed8f | 481 | ///Clears the screen buffer and runs init functions |
avi23 | 7:babc367a3333 | 482 | memset(screen_buffer, 0, sizeof(screen_buffer)); |
avi23 | 7:babc367a3333 | 483 | no_of_alive_invaders = 15; |
avi23 | 7:babc367a3333 | 484 | score = 0; |
avi23 | 7:babc367a3333 | 485 | number_of_lives = 3; |
avi23 | 8:b2faec20ed8f | 486 | down_count = 0; |
avi23 | 8:b2faec20ed8f | 487 | cannon_xpos = 15; |
avi23 | 8:b2faec20ed8f | 488 | ufo_bonus = false; |
avi23 | 8:b2faec20ed8f | 489 | shot_count = 0; |
avi23 | 7:babc367a3333 | 490 | InitSmallInvaders(); |
avi23 | 7:babc367a3333 | 491 | InitMediumInvaders(); |
avi23 | 7:babc367a3333 | 492 | InitLargeInvaders(); |
avi23 | 7:babc367a3333 | 493 | InitBarriers(); |
avi23 | 8:b2faec20ed8f | 494 | ///If the sound is set activate the buzzer flag |
avi23 | 8:b2faec20ed8f | 495 | if (!is_muted) { |
avi23 | 8:b2faec20ed8f | 496 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 497 | } |
avi23 | 8:b2faec20ed8f | 498 | ///Sets the flags so enemies pop up straight away |
avi23 | 7:babc367a3333 | 499 | g_update_screen_flag = true; |
avi23 | 7:babc367a3333 | 500 | g_move_joystick_flag = true; |
avi23 | 7:babc367a3333 | 501 | g_move_enemies_flag = true; |
avi23 | 8:b2faec20ed8f | 502 | g_fire_buzzer_flag = true; |
avi23 | 8:b2faec20ed8f | 503 | ///Forces the missiles to have the fired flags to flase |
avi23 | 7:babc367a3333 | 504 | cannon_missile_on_screen = false; |
avi23 | 7:babc367a3333 | 505 | invader_normal_missile[0].fired = false; |
avi23 | 7:babc367a3333 | 506 | invader_normal_missile[1].fired = false; |
avi23 | 7:babc367a3333 | 507 | } |
avi23 | 7:babc367a3333 | 508 | |
avi23 | 5:34855f712350 | 509 | void UpdateScreen() |
avi23 | 2:d34c95990605 | 510 | { |
avi23 | 8:b2faec20ed8f | 511 | ///Loops through the screen buffer and sets pixels on the LCD |
avi23 | 5:34855f712350 | 512 | for (int col = 0; col < 84; ++col) { |
avi23 | 5:34855f712350 | 513 | for (int row = 0; row < 48; ++row) { |
avi23 | 5:34855f712350 | 514 | if (screen_buffer[col][row]) { |
avi23 | 5:34855f712350 | 515 | lcd.setPixel(col, row); |
avi23 | 5:34855f712350 | 516 | } else { |
avi23 | 5:34855f712350 | 517 | lcd.clearPixel(col, row); |
avi23 | 5:34855f712350 | 518 | } |
avi23 | 5:34855f712350 | 519 | } |
avi23 | 5:34855f712350 | 520 | } |
avi23 | 5:34855f712350 | 521 | |
avi23 | 5:34855f712350 | 522 | lcd.refresh(); |
avi23 | 2:d34c95990605 | 523 | } |
avi23 | 2:d34c95990605 | 524 | |
avi23 | 2:d34c95990605 | 525 | void MoveCannon() |
avi23 | 0:427469992efe | 526 | { |
avi23 | 8:b2faec20ed8f | 527 | ///Clears the cannon |
avi23 | 5:34855f712350 | 528 | for (int col = 0; col < 9; ++col) { |
avi23 | 5:34855f712350 | 529 | for (int row = 0; row < 5; ++row) { |
avi23 | 1:b300d052d549 | 530 | if(cannon_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 531 | screen_buffer[cannon_xpos+col][cannon_ypos+row] = empty_pixel; |
avi23 | 0:427469992efe | 532 | } |
avi23 | 0:427469992efe | 533 | } |
avi23 | 0:427469992efe | 534 | } |
avi23 | 0:427469992efe | 535 | |
avi23 | 8:b2faec20ed8f | 536 | ///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 | 537 | if (joystick.GetXValue() < 0.25f) { |
avi23 | 1:b300d052d549 | 538 | cannon_xpos--; |
avi23 | 1:b300d052d549 | 539 | if (cannon_xpos < 0) { |
avi23 | 1:b300d052d549 | 540 | cannon_xpos = 0; |
avi23 | 0:427469992efe | 541 | } |
avi23 | 0:427469992efe | 542 | } else if (joystick.GetXValue() > 0.75f) { |
avi23 | 1:b300d052d549 | 543 | cannon_xpos++; |
avi23 | 1:b300d052d549 | 544 | if (cannon_xpos > 75) { |
avi23 | 1:b300d052d549 | 545 | cannon_xpos = 75; |
avi23 | 0:427469992efe | 546 | } |
avi23 | 0:427469992efe | 547 | } |
avi23 | 0:427469992efe | 548 | |
avi23 | 8:b2faec20ed8f | 549 | ///Redraws the cannon |
avi23 | 5:34855f712350 | 550 | for (int col = 0; col < 9; ++col) { |
avi23 | 5:34855f712350 | 551 | for (int row = 0; row < 5; ++row) { |
avi23 | 1:b300d052d549 | 552 | if(cannon_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 553 | screen_buffer[cannon_xpos+col][cannon_ypos+row] = cannon_pixel; |
avi23 | 0:427469992efe | 554 | } |
avi23 | 0:427469992efe | 555 | } |
avi23 | 0:427469992efe | 556 | } |
avi23 | 0:427469992efe | 557 | } |
avi23 | 0:427469992efe | 558 | |
avi23 | 8:b2faec20ed8f | 559 | ///Sets the position and status of the small invaders |
avi23 | 0:427469992efe | 560 | void InitSmallInvaders() |
avi23 | 0:427469992efe | 561 | { |
avi23 | 5:34855f712350 | 562 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 563 | small_invader[i].x_pos = 2 + (i*13); /// Large invaders are 12 across so add 13 for a gap space |
avi23 | 2:d34c95990605 | 564 | small_invader[i].y_pos = 1; |
avi23 | 5:34855f712350 | 565 | small_invader[i].status = alive; |
avi23 | 0:427469992efe | 566 | } |
avi23 | 0:427469992efe | 567 | } |
avi23 | 0:427469992efe | 568 | |
avi23 | 8:b2faec20ed8f | 569 | ///Cycles through all the small invaders. If they're not already dead clear them |
avi23 | 2:d34c95990605 | 570 | void ClearSmallInvaders() |
avi23 | 2:d34c95990605 | 571 | { |
avi23 | 5:34855f712350 | 572 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 573 | if (small_invader[i].status) { |
avi23 | 5:34855f712350 | 574 | ClearSingleSmallInvader(i); |
avi23 | 5:34855f712350 | 575 | } |
avi23 | 5:34855f712350 | 576 | } |
avi23 | 5:34855f712350 | 577 | } |
avi23 | 5:34855f712350 | 578 | |
avi23 | 8:b2faec20ed8f | 579 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0 |
avi23 | 5:34855f712350 | 580 | void ClearSingleSmallInvader(int invader_no) |
avi23 | 5:34855f712350 | 581 | { |
avi23 | 5:34855f712350 | 582 | for (int col = 0; col < 8; ++col) { |
avi23 | 5:34855f712350 | 583 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 584 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 585 | if (small_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 586 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 587 | } |
avi23 | 5:34855f712350 | 588 | } else { |
avi23 | 5:34855f712350 | 589 | if (small_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 590 | screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 591 | } |
avi23 | 2:d34c95990605 | 592 | } |
avi23 | 2:d34c95990605 | 593 | } |
avi23 | 2:d34c95990605 | 594 | } |
avi23 | 5:34855f712350 | 595 | |
avi23 | 5:34855f712350 | 596 | small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 2:d34c95990605 | 597 | } |
avi23 | 2:d34c95990605 | 598 | |
avi23 | 8:b2faec20ed8f | 599 | ///Cycles through all the small invaders. If they're alive set them in the screen buffer |
avi23 | 0:427469992efe | 600 | void DrawSmallInvaders() |
avi23 | 0:427469992efe | 601 | { |
avi23 | 5:34855f712350 | 602 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 603 | if (small_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 604 | DrawSingleSmallInvader(i); |
avi23 | 5:34855f712350 | 605 | } |
avi23 | 5:34855f712350 | 606 | } |
avi23 | 5:34855f712350 | 607 | } |
avi23 | 5:34855f712350 | 608 | |
avi23 | 8:b2faec20ed8f | 609 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 610 | void DrawSingleSmallInvader(int invader_no) |
avi23 | 5:34855f712350 | 611 | { |
avi23 | 5:34855f712350 | 612 | for (int col = 0; col < 8; ++col) { |
avi23 | 5:34855f712350 | 613 | for (int row = 0; row < 6; ++row) { |
avi23 | 2:d34c95990605 | 614 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 615 | if (small_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 616 | 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 | 617 | } |
avi23 | 0:427469992efe | 618 | } else { |
avi23 | 5:34855f712350 | 619 | if (small_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 620 | 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 | 621 | } |
avi23 | 0:427469992efe | 622 | } |
avi23 | 0:427469992efe | 623 | } |
avi23 | 0:427469992efe | 624 | } |
avi23 | 1:b300d052d549 | 625 | } |
avi23 | 1:b300d052d549 | 626 | |
avi23 | 8:b2faec20ed8f | 627 | ///Sets the position and aliveness of the medium invaders |
avi23 | 1:b300d052d549 | 628 | void InitMediumInvaders() |
avi23 | 1:b300d052d549 | 629 | { |
avi23 | 5:34855f712350 | 630 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 631 | medium_invader[i].x_pos = 1 + (i*13); /// Large invaders are 12 across so add 13 for a gap space |
avi23 | 2:d34c95990605 | 632 | medium_invader[i].y_pos = 8; |
avi23 | 5:34855f712350 | 633 | medium_invader[i].status = alive; |
avi23 | 1:b300d052d549 | 634 | } |
avi23 | 1:b300d052d549 | 635 | } |
avi23 | 1:b300d052d549 | 636 | |
avi23 | 8:b2faec20ed8f | 637 | ///Cycles through all the medium invaders. If they're not already dead clear them |
avi23 | 2:d34c95990605 | 638 | void ClearMediumInvaders() |
avi23 | 2:d34c95990605 | 639 | { |
avi23 | 5:34855f712350 | 640 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 641 | if (medium_invader[i].status) { |
avi23 | 5:34855f712350 | 642 | ClearSingleMediumInvader(i); |
avi23 | 2:d34c95990605 | 643 | } |
avi23 | 2:d34c95990605 | 644 | } |
avi23 | 2:d34c95990605 | 645 | } |
avi23 | 2:d34c95990605 | 646 | |
avi23 | 8:b2faec20ed8f | 647 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0 |
avi23 | 5:34855f712350 | 648 | void ClearSingleMediumInvader(int invader_no) |
avi23 | 5:34855f712350 | 649 | { |
avi23 | 5:34855f712350 | 650 | for (int col = 0; col < 10; ++col) { |
avi23 | 5:34855f712350 | 651 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 652 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 653 | if (medium_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 654 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 655 | } |
avi23 | 5:34855f712350 | 656 | } else { |
avi23 | 5:34855f712350 | 657 | if (medium_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 658 | screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 659 | } |
avi23 | 5:34855f712350 | 660 | } |
avi23 | 5:34855f712350 | 661 | } |
avi23 | 5:34855f712350 | 662 | } |
avi23 | 5:34855f712350 | 663 | |
avi23 | 5:34855f712350 | 664 | medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 5:34855f712350 | 665 | } |
avi23 | 5:34855f712350 | 666 | |
avi23 | 8:b2faec20ed8f | 667 | ///Cycles through all the medium invaders. If they're alive set them in the screen buffer |
avi23 | 1:b300d052d549 | 668 | void DrawMediumInvaders() |
avi23 | 1:b300d052d549 | 669 | { |
avi23 | 5:34855f712350 | 670 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 671 | if (medium_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 672 | DrawSingleMediumInvader(i); |
avi23 | 5:34855f712350 | 673 | } |
avi23 | 5:34855f712350 | 674 | } |
avi23 | 5:34855f712350 | 675 | } |
avi23 | 5:34855f712350 | 676 | |
avi23 | 8:b2faec20ed8f | 677 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 678 | void DrawSingleMediumInvader(int invader_no) |
avi23 | 5:34855f712350 | 679 | { |
avi23 | 5:34855f712350 | 680 | for (int col = 0; col < 10; ++col) { |
avi23 | 5:34855f712350 | 681 | for (int row = 0; row < 6; ++row) { |
avi23 | 2:d34c95990605 | 682 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 683 | if (medium_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 684 | 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 | 685 | } |
avi23 | 1:b300d052d549 | 686 | } else { |
avi23 | 5:34855f712350 | 687 | if (medium_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 688 | 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 | 689 | } |
avi23 | 1:b300d052d549 | 690 | } |
avi23 | 1:b300d052d549 | 691 | } |
avi23 | 1:b300d052d549 | 692 | } |
avi23 | 1:b300d052d549 | 693 | } |
avi23 | 1:b300d052d549 | 694 | |
avi23 | 8:b2faec20ed8f | 695 | ///Sets the position and status of the large invaders |
avi23 | 1:b300d052d549 | 696 | void InitLargeInvaders() |
avi23 | 1:b300d052d549 | 697 | { |
avi23 | 5:34855f712350 | 698 | for (int i = 0; i < 5; ++i) { |
avi23 | 1:b300d052d549 | 699 | large_invader[i].x_pos = 0 + (i*13); |
avi23 | 2:d34c95990605 | 700 | large_invader[i].y_pos = 15; |
avi23 | 5:34855f712350 | 701 | large_invader[i].status = alive; |
avi23 | 5:34855f712350 | 702 | } |
avi23 | 5:34855f712350 | 703 | } |
avi23 | 5:34855f712350 | 704 | |
avi23 | 8:b2faec20ed8f | 705 | ///Cycles through all the large invaders. If they're not already dead clear them |
avi23 | 5:34855f712350 | 706 | void ClearLargeInvaders() |
avi23 | 5:34855f712350 | 707 | { |
avi23 | 5:34855f712350 | 708 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 709 | if (large_invader[i].status) { |
avi23 | 5:34855f712350 | 710 | ClearSingleLargeInvader(i); |
avi23 | 5:34855f712350 | 711 | } |
avi23 | 1:b300d052d549 | 712 | } |
avi23 | 1:b300d052d549 | 713 | } |
avi23 | 1:b300d052d549 | 714 | |
avi23 | 8:b2faec20ed8f | 715 | ///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 | 716 | void ClearSingleLargeInvader(int invader_no) |
avi23 | 2:d34c95990605 | 717 | { |
avi23 | 5:34855f712350 | 718 | for (int col = 0; col < 12; ++col) { |
avi23 | 5:34855f712350 | 719 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 720 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 721 | if (large_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 722 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 723 | } |
avi23 | 5:34855f712350 | 724 | } else { |
avi23 | 5:34855f712350 | 725 | if (large_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 726 | screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 727 | } |
avi23 | 2:d34c95990605 | 728 | } |
avi23 | 5:34855f712350 | 729 | } |
avi23 | 5:34855f712350 | 730 | } |
avi23 | 5:34855f712350 | 731 | |
avi23 | 5:34855f712350 | 732 | large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive; |
avi23 | 5:34855f712350 | 733 | } |
avi23 | 5:34855f712350 | 734 | |
avi23 | 8:b2faec20ed8f | 735 | ///Cycles through all the large invaders. If they're alive set them in the screen buffer |
avi23 | 5:34855f712350 | 736 | void DrawLargeInvaders() |
avi23 | 5:34855f712350 | 737 | { |
avi23 | 5:34855f712350 | 738 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 739 | if (large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 740 | DrawSingleLargeInvader(i); |
avi23 | 5:34855f712350 | 741 | } |
avi23 | 5:34855f712350 | 742 | } |
avi23 | 5:34855f712350 | 743 | } |
avi23 | 5:34855f712350 | 744 | |
avi23 | 8:b2faec20ed8f | 745 | ///Cycles through the the screen invader bitmap and sets the pixels in the buffer |
avi23 | 5:34855f712350 | 746 | void DrawSingleLargeInvader(int invader_no) |
avi23 | 5:34855f712350 | 747 | { |
avi23 | 5:34855f712350 | 748 | for (int col = 0; col < 12; ++col) { |
avi23 | 5:34855f712350 | 749 | for (int row = 0; row < 6; ++row) { |
avi23 | 5:34855f712350 | 750 | if (invaders_in_state2) { |
avi23 | 5:34855f712350 | 751 | if (large_invader_bitmap_1[row][col]) { |
avi23 | 5:34855f712350 | 752 | 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 | 753 | } |
avi23 | 5:34855f712350 | 754 | } else { |
avi23 | 5:34855f712350 | 755 | if (large_invader_bitmap_2[row][col]) { |
avi23 | 5:34855f712350 | 756 | 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 | 757 | } |
avi23 | 2:d34c95990605 | 758 | } |
avi23 | 2:d34c95990605 | 759 | } |
avi23 | 2:d34c95990605 | 760 | } |
avi23 | 2:d34c95990605 | 761 | } |
avi23 | 2:d34c95990605 | 762 | |
avi23 | 8:b2faec20ed8f | 763 | ///Sets the position and loads the bitmap into the barrier objects |
avi23 | 2:d34c95990605 | 764 | void InitBarriers() |
avi23 | 2:d34c95990605 | 765 | { |
avi23 | 5:34855f712350 | 766 | for (int i = 0; i < 3; ++i) { |
avi23 | 2:d34c95990605 | 767 | barrier[i].x_pos = 10 + (i*25); |
avi23 | 2:d34c95990605 | 768 | barrier[i].y_pos = 33; |
avi23 | 8:b2faec20ed8f | 769 | ///Copies the bitmap into the structs |
avi23 | 2:d34c95990605 | 770 | memcpy(barrier[i].before_bitmap, barrier_bitmap, sizeof(barrier_bitmap)); |
avi23 | 2:d34c95990605 | 771 | memcpy(barrier[i].after_bitmap, barrier_bitmap, sizeof(barrier_bitmap)); |
avi23 | 2:d34c95990605 | 772 | } |
avi23 | 2:d34c95990605 | 773 | } |
avi23 | 2:d34c95990605 | 774 | |
avi23 | 2:d34c95990605 | 775 | void DrawBarriers() |
avi23 | 2:d34c95990605 | 776 | { |
avi23 | 8:b2faec20ed8f | 777 | ///Clears the barrier and redraws it with damage applied |
avi23 | 5:34855f712350 | 778 | for (int i = 0; i < 3; ++i) { |
avi23 | 5:34855f712350 | 779 | for (int col = 0; col < 14; ++col) { |
avi23 | 5:34855f712350 | 780 | for (int row = 0; row < 8; ++row) { |
avi23 | 2:d34c95990605 | 781 | if (barrier[i].before_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 782 | screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel; |
avi23 | 2:d34c95990605 | 783 | } |
avi23 | 2:d34c95990605 | 784 | if (barrier[i].after_bitmap[row][col]) { |
avi23 | 5:34855f712350 | 785 | screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i; |
avi23 | 2:d34c95990605 | 786 | } |
avi23 | 2:d34c95990605 | 787 | } |
avi23 | 2:d34c95990605 | 788 | } |
avi23 | 8:b2faec20ed8f | 789 | ///Copies the after array to the before array |
avi23 | 2:d34c95990605 | 790 | memcpy(barrier[i].before_bitmap, barrier[i].after_bitmap, sizeof(barrier[i].after_bitmap)); |
avi23 | 2:d34c95990605 | 791 | } |
avi23 | 2:d34c95990605 | 792 | } |
avi23 | 2:d34c95990605 | 793 | |
avi23 | 5:34855f712350 | 794 | void MoveInvaderXPositions() |
avi23 | 2:d34c95990605 | 795 | { |
avi23 | 8:b2faec20ed8f | 796 | ///Moves the invader in the current direction |
avi23 | 2:d34c95990605 | 797 | if (invader_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 798 | ///Checking the right limit |
avi23 | 7:babc367a3333 | 799 | int right_invader_limit = CalculateInvaderRightLimit(); |
avi23 | 5:34855f712350 | 800 | MoveInvadersRight(right_invader_limit); |
avi23 | 5:34855f712350 | 801 | } else { |
avi23 | 8:b2faec20ed8f | 802 | ///Checks the left limit |
avi23 | 7:babc367a3333 | 803 | int left_invader_limit = CalculateInvaderLeftLimit(); |
avi23 | 5:34855f712350 | 804 | MoveInvadersLeft(left_invader_limit); |
avi23 | 5:34855f712350 | 805 | } |
avi23 | 5:34855f712350 | 806 | } |
avi23 | 5:34855f712350 | 807 | |
avi23 | 8:b2faec20ed8f | 808 | ///Checks the status off the invaders per column, starting from the left |
avi23 | 8:b2faec20ed8f | 809 | ///If they're alive return the row number |
avi23 | 5:34855f712350 | 810 | int CalculateInvaderLeftLimit() |
avi23 | 5:34855f712350 | 811 | { |
avi23 | 5:34855f712350 | 812 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 813 | if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 814 | return i; |
avi23 | 5:34855f712350 | 815 | } |
avi23 | 5:34855f712350 | 816 | } |
avi23 | 5:34855f712350 | 817 | |
avi23 | 8:b2faec20ed8f | 818 | ///Sort gameover out stuff after |
avi23 | 5:34855f712350 | 819 | return 4; |
avi23 | 5:34855f712350 | 820 | } |
avi23 | 5:34855f712350 | 821 | |
avi23 | 8:b2faec20ed8f | 822 | ///Checks the status off the invaders per column, starting from the right |
avi23 | 8:b2faec20ed8f | 823 | ///If they're alive return the row number |
avi23 | 5:34855f712350 | 824 | int CalculateInvaderRightLimit() |
avi23 | 5:34855f712350 | 825 | { |
avi23 | 5:34855f712350 | 826 | for (int i = 4; i >= 0; --i) { |
avi23 | 5:34855f712350 | 827 | if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) { |
avi23 | 5:34855f712350 | 828 | return i; |
avi23 | 5:34855f712350 | 829 | } |
avi23 | 5:34855f712350 | 830 | } |
avi23 | 5:34855f712350 | 831 | |
avi23 | 8:b2faec20ed8f | 832 | ///Sort gameover stuff |
avi23 | 5:34855f712350 | 833 | return 0; |
avi23 | 5:34855f712350 | 834 | } |
avi23 | 5:34855f712350 | 835 | |
avi23 | 5:34855f712350 | 836 | void MoveInvadersLeft(int limit) |
avi23 | 5:34855f712350 | 837 | { |
avi23 | 8:b2faec20ed8f | 838 | ///Checks the first large invader to see if it can travel anymore |
avi23 | 5:34855f712350 | 839 | if (large_invader[limit].x_pos > 1) { |
avi23 | 5:34855f712350 | 840 | for (int i = 0; i < 5; ++i) { |
avi23 | 8:b2faec20ed8f | 841 | ///Moves the invaders 2 to the left |
avi23 | 5:34855f712350 | 842 | small_invader[i].x_pos -= 2; |
avi23 | 5:34855f712350 | 843 | medium_invader[i].x_pos -= 2; |
avi23 | 5:34855f712350 | 844 | large_invader[i].x_pos -= 2; |
avi23 | 2:d34c95990605 | 845 | } |
avi23 | 2:d34c95990605 | 846 | } else { |
avi23 | 8:b2faec20ed8f | 847 | ///Shifts the Invaders down and passes in the new direction |
avi23 | 5:34855f712350 | 848 | MoveInvaderYPositions(RIGHT); |
avi23 | 2:d34c95990605 | 849 | } |
avi23 | 2:d34c95990605 | 850 | } |
avi23 | 2:d34c95990605 | 851 | |
avi23 | 5:34855f712350 | 852 | void MoveInvadersRight(int limit) |
avi23 | 2:d34c95990605 | 853 | { |
avi23 | 8:b2faec20ed8f | 854 | ///Checks the first large invader to see if it can travel anymore |
avi23 | 5:34855f712350 | 855 | if (large_invader[limit].x_pos < 71) { |
avi23 | 8:b2faec20ed8f | 856 | ///Moves the invaders 2 to the right |
avi23 | 5:34855f712350 | 857 | for (int i = 0; i < 5; ++i) { |
avi23 | 5:34855f712350 | 858 | small_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 859 | medium_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 860 | large_invader[i].x_pos += 2; |
avi23 | 5:34855f712350 | 861 | } |
avi23 | 2:d34c95990605 | 862 | } else { |
avi23 | 8:b2faec20ed8f | 863 | ///Shifts the Invaders down and passes in the new direction |
avi23 | 5:34855f712350 | 864 | MoveInvaderYPositions(LEFT); |
avi23 | 2:d34c95990605 | 865 | } |
avi23 | 5:34855f712350 | 866 | } |
avi23 | 5:34855f712350 | 867 | |
avi23 | 5:34855f712350 | 868 | void MoveInvaderYPositions(bool new_direction) |
avi23 | 5:34855f712350 | 869 | { |
avi23 | 8:b2faec20ed8f | 870 | ///Finds the invaders lower limit |
avi23 | 5:34855f712350 | 871 | Invader lowest_invader = CalculateInvaderYLimit(); |
avi23 | 5:34855f712350 | 872 | |
avi23 | 8:b2faec20ed8f | 873 | ///When moving down lowest_invader should not equal none |
avi23 | 5:34855f712350 | 874 | if (lowest_invader == none) { |
avi23 | 5:34855f712350 | 875 | error(); |
avi23 | 5:34855f712350 | 876 | } |
avi23 | 5:34855f712350 | 877 | |
avi23 | 8:b2faec20ed8f | 878 | ///If an invader touches the bottom the game ends, otherwise the invaders descend |
avi23 | 5:34855f712350 | 879 | if (small_invader[0].y_pos < 33 - (7*lowest_invader)) { |
avi23 | 5:34855f712350 | 880 | for (int i = 0; i < 5; ++i) { |
avi23 | 2:d34c95990605 | 881 | small_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 882 | medium_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 883 | large_invader[i].y_pos += 3; |
avi23 | 2:d34c95990605 | 884 | } |
avi23 | 8:b2faec20ed8f | 885 | ++down_count; |
avi23 | 5:34855f712350 | 886 | invader_direction = new_direction; |
avi23 | 5:34855f712350 | 887 | } else { |
avi23 | 5:34855f712350 | 888 | number_of_lives = 0; |
avi23 | 5:34855f712350 | 889 | } |
avi23 | 5:34855f712350 | 890 | } |
avi23 | 5:34855f712350 | 891 | |
avi23 | 5:34855f712350 | 892 | Invader CalculateInvaderYLimit() |
avi23 | 5:34855f712350 | 893 | { |
avi23 | 8:b2faec20ed8f | 894 | ///Checks to see which row of invaders are still alive to work out maximum y positions |
avi23 | 5:34855f712350 | 895 | 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 | 896 | return large; |
avi23 | 5:34855f712350 | 897 | } 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 | 898 | return medium; |
avi23 | 2:d34c95990605 | 899 | } else { |
avi23 | 5:34855f712350 | 900 | return small; |
avi23 | 2:d34c95990605 | 901 | } |
avi23 | 5:34855f712350 | 902 | } |
avi23 | 2:d34c95990605 | 903 | |
avi23 | 8:b2faec20ed8f | 904 | ///Queries the invaders on their status and returns the type of invader which is alive |
avi23 | 5:34855f712350 | 905 | Invader LowestInvaderInColumn(int column) |
avi23 | 5:34855f712350 | 906 | { |
avi23 | 5:34855f712350 | 907 | if (large_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 908 | return large; |
avi23 | 5:34855f712350 | 909 | } else if (medium_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 910 | return medium; |
avi23 | 5:34855f712350 | 911 | } else if (small_invader[column].status == alive) { |
avi23 | 5:34855f712350 | 912 | return small; |
avi23 | 5:34855f712350 | 913 | } else { |
avi23 | 5:34855f712350 | 914 | return none; |
avi23 | 5:34855f712350 | 915 | } |
avi23 | 2:d34c95990605 | 916 | } |
avi23 | 2:d34c95990605 | 917 | |
avi23 | 5:34855f712350 | 918 | void FireCannonMissile() |
avi23 | 5:34855f712350 | 919 | { |
avi23 | 8:b2faec20ed8f | 920 | ///Sets the cannon fired flag to true |
avi23 | 5:34855f712350 | 921 | cannon_missile_on_screen = true; |
avi23 | 5:34855f712350 | 922 | |
avi23 | 8:b2faec20ed8f | 923 | ///Offset cannon missile x position by 4 of the cannons x pos |
avi23 | 5:34855f712350 | 924 | cannon_missile_x_pos = cannon_xpos + 4; |
avi23 | 8:b2faec20ed8f | 925 | ///Will always have a starting y of 40 |
avi23 | 5:34855f712350 | 926 | cannon_missile_y_pos = 40; |
avi23 | 8:b2faec20ed8f | 927 | ///Attach the move cannon missile |
avi23 | 5:34855f712350 | 928 | move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); |
avi23 | 5:34855f712350 | 929 | } |
avi23 | 5:34855f712350 | 930 | |
avi23 | 5:34855f712350 | 931 | void MoveCannonMissile() |
avi23 | 5:34855f712350 | 932 | { |
avi23 | 8:b2faec20ed8f | 933 | ///Checks bullet will not go beyond the bounds of the screen buffer |
avi23 | 5:34855f712350 | 934 | if (cannon_missile_y_pos > -1) { |
avi23 | 8:b2faec20ed8f | 935 | ///Loops throught the shot bitmap and clears the pixels in the screen buffer |
avi23 | 5:34855f712350 | 936 | for (int row = 0; row < 4; ++row) { |
avi23 | 8:b2faec20ed8f | 937 | ///Clears the position where the bullet was |
avi23 | 5:34855f712350 | 938 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 939 | } |
avi23 | 5:34855f712350 | 940 | |
avi23 | 8:b2faec20ed8f | 941 | ///Increments the shot going up the screen |
avi23 | 5:34855f712350 | 942 | --cannon_missile_y_pos; |
avi23 | 5:34855f712350 | 943 | |
avi23 | 8:b2faec20ed8f | 944 | ///Checks to see if the shot will hit anything |
avi23 | 5:34855f712350 | 945 | CollisionDetectionCannonMissile(); |
avi23 | 5:34855f712350 | 946 | } else { |
avi23 | 8:b2faec20ed8f | 947 | ///Loops throught the shot bitmap and clears the pixels in the screen buffer |
avi23 | 5:34855f712350 | 948 | for (int row = 1; row < 4; ++row) { |
avi23 | 8:b2faec20ed8f | 949 | ///Clears the position where the bullet was |
avi23 | 5:34855f712350 | 950 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel; |
avi23 | 5:34855f712350 | 951 | } |
avi23 | 5:34855f712350 | 952 | |
avi23 | 5:34855f712350 | 953 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 954 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 955 | } |
avi23 | 5:34855f712350 | 956 | } |
avi23 | 5:34855f712350 | 957 | |
avi23 | 8:b2faec20ed8f | 958 | ///Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer |
avi23 | 5:34855f712350 | 959 | void CollisionDetectionCannonMissile() |
avi23 | 5:34855f712350 | 960 | { |
avi23 | 5:34855f712350 | 961 | for (int row = 0; row < 4; ++row) { |
avi23 | 5:34855f712350 | 962 | int object_no; |
avi23 | 7:babc367a3333 | 963 | int pixel_check = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row]; |
avi23 | 8:b2faec20ed8f | 964 | if (pixel_check >= first_small_invader_pixel && pixel_check < ufo_pixel) { ///Collides with a small invader |
avi23 | 8:b2faec20ed8f | 965 | ///Find the object no of the small invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 966 | object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader); |
avi23 | 5:34855f712350 | 967 | ClearSingleSmallInvader(object_no); |
avi23 | 5:34855f712350 | 968 | score += 40; |
avi23 | 5:34855f712350 | 969 | break; |
avi23 | 8:b2faec20ed8f | 970 | } else if (pixel_check >= first_medium_invader_pixel && pixel_check < first_small_invader_pixel) { ///Collides with a medium invader |
avi23 | 8:b2faec20ed8f | 971 | ///Find the object no of the medium invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 972 | object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader); |
avi23 | 5:34855f712350 | 973 | ClearSingleMediumInvader(object_no); |
avi23 | 5:34855f712350 | 974 | score += 20; |
avi23 | 5:34855f712350 | 975 | break; |
avi23 | 8:b2faec20ed8f | 976 | } else if (pixel_check >= first_large_invader_pixel && pixel_check < first_medium_invader_pixel) { ///Collides with a large invader |
avi23 | 8:b2faec20ed8f | 977 | ///Find the object no of the large invader it hit, clears it and increments the score |
avi23 | 5:34855f712350 | 978 | object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader); |
avi23 | 5:34855f712350 | 979 | ClearSingleLargeInvader(object_no); |
avi23 | 5:34855f712350 | 980 | score += 10; |
avi23 | 5:34855f712350 | 981 | break; |
avi23 | 8:b2faec20ed8f | 982 | } else if (pixel_check >= first_barrier_pixel && pixel_check < (first_barrier_pixel + 3)) { ///Collides with a barrier |
avi23 | 8:b2faec20ed8f | 983 | ///Adds the destruction done to the barrier to the bitmap and redraws the barriers |
avi23 | 7:babc367a3333 | 984 | CannonMissileHitBarrier(row); |
avi23 | 5:34855f712350 | 985 | DrawBarriers(); |
avi23 | 5:34855f712350 | 986 | break; |
avi23 | 8:b2faec20ed8f | 987 | } else if (pixel_check == ufo_pixel) { ///Collides with a UFO |
avi23 | 8:b2faec20ed8f | 988 | ///Clears the UFO, calculates score depending on the ufo bonus |
avi23 | 8:b2faec20ed8f | 989 | ClearUFO(); |
avi23 | 8:b2faec20ed8f | 990 | ufo_on_screen = false; |
avi23 | 8:b2faec20ed8f | 991 | move_ufo.detach(); |
avi23 | 8:b2faec20ed8f | 992 | if (ufo_bonus && shot_count == 15) { ///If the shot bonus is active and on the 15th shot, give 300 points |
avi23 | 8:b2faec20ed8f | 993 | score += 300; |
avi23 | 8:b2faec20ed8f | 994 | } 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 | 8:b2faec20ed8f | 995 | ufo_bonus = true; |
avi23 | 8:b2faec20ed8f | 996 | score += 300; |
avi23 | 8:b2faec20ed8f | 997 | } else { ///Randomly assign score between 50, 100, 150 points |
avi23 | 8:b2faec20ed8f | 998 | score += 50 * ((rand() % 3) + 1); |
avi23 | 8:b2faec20ed8f | 999 | } |
avi23 | 5:34855f712350 | 1000 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 1001 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 1002 | break; |
avi23 | 5:34855f712350 | 1003 | } else { |
avi23 | 5:34855f712350 | 1004 | screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = cannon_missile_pixel; |
avi23 | 5:34855f712350 | 1005 | } |
avi23 | 5:34855f712350 | 1006 | } |
avi23 | 5:34855f712350 | 1007 | } |
avi23 | 5:34855f712350 | 1008 | |
avi23 | 8:b2faec20ed8f | 1009 | ///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 | 1010 | int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]) |
avi23 | 5:34855f712350 | 1011 | { |
avi23 | 5:34855f712350 | 1012 | int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel; |
avi23 | 5:34855f712350 | 1013 | invader[invader_no].status = dying; |
avi23 | 5:34855f712350 | 1014 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 1015 | --no_of_alive_invaders; |
avi23 | 5:34855f712350 | 1016 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 1017 | |
avi23 | 5:34855f712350 | 1018 | return invader_no; |
avi23 | 5:34855f712350 | 1019 | } |
avi23 | 5:34855f712350 | 1020 | |
avi23 | 8:b2faec20ed8f | 1021 | ///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation |
avi23 | 7:babc367a3333 | 1022 | void CannonMissileHitBarrier(int row) |
avi23 | 5:34855f712350 | 1023 | { |
avi23 | 7:babc367a3333 | 1024 | int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_barrier_pixel; |
avi23 | 8:b2faec20ed8f | 1025 | ///Essentially inverse of barrier init |
avi23 | 5:34855f712350 | 1026 | int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1; |
avi23 | 8:b2faec20ed8f | 1027 | int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; ///Don't know why it's -1 and not -2 |
avi23 | 8:b2faec20ed8f | 1028 | ///Loops through the damage bitmap and modifies the barrier's after bitmap |
avi23 | 5:34855f712350 | 1029 | for (int col = 0; col < 3; ++col) { |
avi23 | 5:34855f712350 | 1030 | for (int row_bit = 0; row_bit < 3; ++row_bit) { |
avi23 | 8:b2faec20ed8f | 1031 | ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration |
avi23 | 8:b2faec20ed8f | 1032 | ///Element by element multiplication of the 2 bitmaps to clear the required pixals |
avi23 | 5:34855f712350 | 1033 | 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 | 1034 | 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 | 1035 | } |
avi23 | 5:34855f712350 | 1036 | } |
avi23 | 5:34855f712350 | 1037 | } |
avi23 | 5:34855f712350 | 1038 | cannon_missile_on_screen = false; |
avi23 | 5:34855f712350 | 1039 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 1040 | } |
avi23 | 5:34855f712350 | 1041 | |
avi23 | 5:34855f712350 | 1042 | void AttemptToFireInvaderNormalMissiles() |
avi23 | 5:34855f712350 | 1043 | { |
avi23 | 8:b2faec20ed8f | 1044 | ///Fires the normal missiles |
avi23 | 8:b2faec20ed8f | 1045 | ///Loops through the 2 allowed missiles and if they're not on the screen, randomly fire |
avi23 | 5:34855f712350 | 1046 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 1047 | if (!invader_normal_missile[i].fired) { |
avi23 | 8:b2faec20ed8f | 1048 | ///If the random mumber is 1, fire a missile |
avi23 | 8:b2faec20ed8f | 1049 | ///Higher chance when there are less invaders on the screen, up to a 1/3 chance |
avi23 | 5:34855f712350 | 1050 | if ((rand() % (no_of_alive_invaders + 2)) == 1) { |
avi23 | 5:34855f712350 | 1051 | int fired_column; |
avi23 | 8:b2faec20ed8f | 1052 | int loop_limit = 0; ///Stops loop from never ending |
avi23 | 5:34855f712350 | 1053 | Invader missile_source; |
avi23 | 5:34855f712350 | 1054 | do { |
avi23 | 5:34855f712350 | 1055 | fired_column = rand() % 5; |
avi23 | 5:34855f712350 | 1056 | missile_source = LowestInvaderInColumn(fired_column); |
avi23 | 5:34855f712350 | 1057 | ++loop_limit; |
avi23 | 5:34855f712350 | 1058 | } while (missile_source == none && loop_limit < 10); |
avi23 | 5:34855f712350 | 1059 | |
avi23 | 8:b2faec20ed8f | 1060 | ///Finds the centre point of the chosen invader and fires the missile |
avi23 | 8:b2faec20ed8f | 1061 | ///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 | 1062 | if (missile_source == none) { |
avi23 | 5:34855f712350 | 1063 | continue; |
avi23 | 5:34855f712350 | 1064 | } else if (missile_source == large) { |
avi23 | 5:34855f712350 | 1065 | FireNormalInvaderMissile(i, missile_source, large_invader[fired_column]); |
avi23 | 5:34855f712350 | 1066 | } else if (missile_source == medium) { |
avi23 | 5:34855f712350 | 1067 | FireNormalInvaderMissile(i, missile_source, medium_invader[fired_column]); |
avi23 | 5:34855f712350 | 1068 | } else { |
avi23 | 5:34855f712350 | 1069 | FireNormalInvaderMissile(i, missile_source, small_invader[fired_column]); |
avi23 | 5:34855f712350 | 1070 | } |
avi23 | 5:34855f712350 | 1071 | } |
avi23 | 5:34855f712350 | 1072 | } |
avi23 | 5:34855f712350 | 1073 | } |
avi23 | 5:34855f712350 | 1074 | } |
avi23 | 5:34855f712350 | 1075 | |
avi23 | 5:34855f712350 | 1076 | void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader)) |
avi23 | 5:34855f712350 | 1077 | { |
avi23 | 8:b2faec20ed8f | 1078 | ///Finds the centre point of the chosen invader and fires the missile |
avi23 | 8:b2faec20ed8f | 1079 | ///Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3 |
avi23 | 5:34855f712350 | 1080 | invader_normal_missile[missile_no].x_pos = invader.x_pos + (3 + source); |
avi23 | 5:34855f712350 | 1081 | invader_normal_missile[missile_no].y_pos = invader.y_pos + 6; |
avi23 | 5:34855f712350 | 1082 | invader_normal_missile[missile_no].fired = true; |
avi23 | 5:34855f712350 | 1083 | |
avi23 | 8:b2faec20ed8f | 1084 | ///Uses a function pointer to attach the ticker |
avi23 | 5:34855f712350 | 1085 | move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05); |
avi23 | 5:34855f712350 | 1086 | } |
avi23 | 5:34855f712350 | 1087 | |
avi23 | 7:babc367a3333 | 1088 | void MoveInvaderNormalMissile(int missile_no) |
avi23 | 7:babc367a3333 | 1089 | { |
avi23 | 8:b2faec20ed8f | 1090 | ///Loops through the bitmap and clears the missile from the screen buffer |
avi23 | 7:babc367a3333 | 1091 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 1092 | for (int row = 0; row < 4; ++row) { |
avi23 | 7:babc367a3333 | 1093 | if (invader_normal_missile_bitmap[row][col]) { |
avi23 | 7:babc367a3333 | 1094 | screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel; |
avi23 | 7:babc367a3333 | 1095 | } |
avi23 | 7:babc367a3333 | 1096 | } |
avi23 | 7:babc367a3333 | 1097 | } |
avi23 | 7:babc367a3333 | 1098 | |
avi23 | 8:b2faec20ed8f | 1099 | ///Checks missile will not exceed screen buffer |
avi23 | 7:babc367a3333 | 1100 | if (invader_normal_missile[missile_no].y_pos < 44) { |
avi23 | 8:b2faec20ed8f | 1101 | ///Increments the position of the missile |
avi23 | 7:babc367a3333 | 1102 | ++invader_normal_missile[missile_no].y_pos; |
avi23 | 7:babc367a3333 | 1103 | |
avi23 | 8:b2faec20ed8f | 1104 | ///Collision detection |
avi23 | 7:babc367a3333 | 1105 | CollisionDetectionInvaderNormalMissile(missile_no); |
avi23 | 7:babc367a3333 | 1106 | |
avi23 | 7:babc367a3333 | 1107 | } else { |
avi23 | 8:b2faec20ed8f | 1108 | ///Sets the missiles fired flag as false and detaches the tickers |
avi23 | 7:babc367a3333 | 1109 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 1110 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 1111 | } |
avi23 | 7:babc367a3333 | 1112 | } |
avi23 | 7:babc367a3333 | 1113 | |
avi23 | 8:b2faec20ed8f | 1114 | ///Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer |
avi23 | 7:babc367a3333 | 1115 | void CollisionDetectionInvaderNormalMissile(int missile_no) |
avi23 | 7:babc367a3333 | 1116 | { |
avi23 | 8:b2faec20ed8f | 1117 | ///Invader missile coordinates shifted to match centre bottom of bitmap |
avi23 | 7:babc367a3333 | 1118 | int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1; |
avi23 | 7:babc367a3333 | 1119 | int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3; |
avi23 | 7:babc367a3333 | 1120 | if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) { |
avi23 | 7:babc367a3333 | 1121 | InvaderNormalMissileHitCannon(); |
avi23 | 7:babc367a3333 | 1122 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 1123 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 1124 | } 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 | 1125 | ///Finds barrier number |
avi23 | 7:babc367a3333 | 1126 | InvaderNormalMissileHitBarrier(invader_normal_missile[missile_no]); |
avi23 | 7:babc367a3333 | 1127 | invader_normal_missile[missile_no].fired = false; |
avi23 | 7:babc367a3333 | 1128 | move_invader_normal_missile[missile_no].detach(); |
avi23 | 7:babc367a3333 | 1129 | } else { |
avi23 | 7:babc367a3333 | 1130 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 1131 | for (int row = 0; row < 4; ++row) { |
avi23 | 7:babc367a3333 | 1132 | if (invader_normal_missile_bitmap[row][col]) { |
avi23 | 7:babc367a3333 | 1133 | 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 | 1134 | } |
avi23 | 7:babc367a3333 | 1135 | } |
avi23 | 7:babc367a3333 | 1136 | } |
avi23 | 7:babc367a3333 | 1137 | } |
avi23 | 7:babc367a3333 | 1138 | } |
avi23 | 7:babc367a3333 | 1139 | |
avi23 | 7:babc367a3333 | 1140 | void InvaderNormalMissileHitCannon() |
avi23 | 7:babc367a3333 | 1141 | { |
avi23 | 8:b2faec20ed8f | 1142 | ///Decrements the number of lives, pauses the game for 2 seconds |
avi23 | 8:b2faec20ed8f | 1143 | ///Marks the cannon as hit |
avi23 | 7:babc367a3333 | 1144 | g_cannon_hit_flag = true; |
avi23 | 8:b2faec20ed8f | 1145 | ///Detaches all tickers |
avi23 | 7:babc367a3333 | 1146 | DetachTickers(); |
avi23 | 8:b2faec20ed8f | 1147 | ///Creates a Timeout object on the stack with a period of 2 seconds to pause the game for 2 seconds |
avi23 | 7:babc367a3333 | 1148 | Timeout cannon_hit; |
avi23 | 7:babc367a3333 | 1149 | cannon_hit.attach(&cannon_hit_isr, 2); |
avi23 | 7:babc367a3333 | 1150 | while (g_cannon_hit_flag) { |
avi23 | 7:babc367a3333 | 1151 | sleep(); |
avi23 | 7:babc367a3333 | 1152 | } |
avi23 | 7:babc367a3333 | 1153 | AttachTickers(); |
avi23 | 7:babc367a3333 | 1154 | --number_of_lives; |
avi23 | 7:babc367a3333 | 1155 | } |
avi23 | 7:babc367a3333 | 1156 | |
avi23 | 8:b2faec20ed8f | 1157 | ///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation |
avi23 | 7:babc367a3333 | 1158 | void InvaderNormalMissileHitBarrier(const struct InvaderNormalMissiles (&missile)) |
avi23 | 7:babc367a3333 | 1159 | { |
avi23 | 7:babc367a3333 | 1160 | int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_barrier_pixel; |
avi23 | 8:b2faec20ed8f | 1161 | ///Essentially inverse of barrier init |
avi23 | 7:babc367a3333 | 1162 | int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1; |
avi23 | 7:babc367a3333 | 1163 | int relative_y_pos = (missile.y_pos + 3) - 33; |
avi23 | 8:b2faec20ed8f | 1164 | ///Loops through the damage bitmap and modifies the barrier's after bitmap |
avi23 | 7:babc367a3333 | 1165 | for (int col = 0; col < 3; ++col) { |
avi23 | 7:babc367a3333 | 1166 | for (int row_bit = 0; row_bit < 2; ++row_bit) { |
avi23 | 8:b2faec20ed8f | 1167 | ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration |
avi23 | 7:babc367a3333 | 1168 | 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 | 1169 | 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 | 1170 | } |
avi23 | 7:babc367a3333 | 1171 | } |
avi23 | 7:babc367a3333 | 1172 | } |
avi23 | 7:babc367a3333 | 1173 | } |
avi23 | 7:babc367a3333 | 1174 | |
avi23 | 8:b2faec20ed8f | 1175 | ///Detaches game related tickers |
avi23 | 5:34855f712350 | 1176 | void DetachTickers() |
avi23 | 5:34855f712350 | 1177 | { |
avi23 | 5:34855f712350 | 1178 | update_screen.detach(); |
avi23 | 5:34855f712350 | 1179 | move_enemies.detach(); |
avi23 | 8:b2faec20ed8f | 1180 | |
avi23 | 8:b2faec20ed8f | 1181 | ///Only detaches if missiles are on the screen |
avi23 | 5:34855f712350 | 1182 | if (cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 1183 | move_cannon_missile.detach(); |
avi23 | 5:34855f712350 | 1184 | } |
avi23 | 5:34855f712350 | 1185 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 1186 | if (invader_normal_missile[i].fired) { |
avi23 | 5:34855f712350 | 1187 | move_invader_normal_missile[i].detach(); |
avi23 | 5:34855f712350 | 1188 | } |
avi23 | 5:34855f712350 | 1189 | } |
avi23 | 5:34855f712350 | 1190 | } |
avi23 | 5:34855f712350 | 1191 | |
avi23 | 8:b2faec20ed8f | 1192 | ///Attaches game related tickers |
avi23 | 5:34855f712350 | 1193 | void AttachTickers() |
avi23 | 5:34855f712350 | 1194 | { |
avi23 | 5:34855f712350 | 1195 | update_screen.attach(&update_screen_isr, 0.05); |
avi23 | 5:34855f712350 | 1196 | move_enemies.attach(&move_enemies_isr, ticker_period); |
avi23 | 8:b2faec20ed8f | 1197 | ///Only attaches if missiles were on the screen |
avi23 | 5:34855f712350 | 1198 | if (cannon_missile_on_screen) { |
avi23 | 5:34855f712350 | 1199 | move_cannon_missile.attach(&move_cannon_missile_isr, 0.05); |
avi23 | 5:34855f712350 | 1200 | } |
avi23 | 5:34855f712350 | 1201 | for (int i = 0; i < 2; ++i) { |
avi23 | 5:34855f712350 | 1202 | if (invader_normal_missile[i].fired) { |
avi23 | 5:34855f712350 | 1203 | move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05); |
avi23 | 5:34855f712350 | 1204 | } |
avi23 | 5:34855f712350 | 1205 | } |
avi23 | 6:89d4a7f7588b | 1206 | } |
avi23 | 6:89d4a7f7588b | 1207 | |
avi23 | 6:89d4a7f7588b | 1208 | void PauseScreen() |
avi23 | 6:89d4a7f7588b | 1209 | { |
avi23 | 8:b2faec20ed8f | 1210 | ///Prints the pause screen, score etc |
avi23 | 7:babc367a3333 | 1211 | PrintPauseScreen(); |
avi23 | 7:babc367a3333 | 1212 | |
avi23 | 6:89d4a7f7588b | 1213 | while (game_state == paused) { |
avi23 | 8:b2faec20ed8f | 1214 | ///Draws the cursor |
avi23 | 8:b2faec20ed8f | 1215 | 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 | 1216 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); ///Draws the cursor |
avi23 | 6:89d4a7f7588b | 1217 | |
avi23 | 6:89d4a7f7588b | 1218 | if (g_move_joystick_flag) { |
avi23 | 6:89d4a7f7588b | 1219 | g_move_joystick_flag = false; |
avi23 | 6:89d4a7f7588b | 1220 | |
avi23 | 8:b2faec20ed8f | 1221 | ///Moves the cursor to match the selected option, only if the joystick isn't centred |
avi23 | 6:89d4a7f7588b | 1222 | MoveCursor(fsm_paused); |
avi23 | 6:89d4a7f7588b | 1223 | } |
avi23 | 6:89d4a7f7588b | 1224 | |
avi23 | 8:b2faec20ed8f | 1225 | ///If the button is pressed the selected option will appear on the screen |
avi23 | 6:89d4a7f7588b | 1226 | if (g_shoot_pressed_flag) { |
avi23 | 6:89d4a7f7588b | 1227 | g_shoot_pressed_flag = false; |
avi23 | 6:89d4a7f7588b | 1228 | game_state = fsm_paused[fsm_state].output; |
avi23 | 6:89d4a7f7588b | 1229 | } |
avi23 | 6:89d4a7f7588b | 1230 | |
avi23 | 8:b2faec20ed8f | 1231 | ///Resets the joystick flag to false if pressed |
avi23 | 6:89d4a7f7588b | 1232 | if (joystick.get_button_flag()) { |
avi23 | 6:89d4a7f7588b | 1233 | joystick.set_button_flag(0); |
avi23 | 6:89d4a7f7588b | 1234 | } |
avi23 | 6:89d4a7f7588b | 1235 | |
avi23 | 6:89d4a7f7588b | 1236 | lcd.refresh(); |
avi23 | 6:89d4a7f7588b | 1237 | |
avi23 | 6:89d4a7f7588b | 1238 | sleep(); |
avi23 | 6:89d4a7f7588b | 1239 | } |
avi23 | 6:89d4a7f7588b | 1240 | } |
avi23 | 6:89d4a7f7588b | 1241 | |
avi23 | 6:89d4a7f7588b | 1242 | void PrintPauseScreen() |
avi23 | 6:89d4a7f7588b | 1243 | { |
avi23 | 8:b2faec20ed8f | 1244 | ///Prints paused and a line underneath |
avi23 | 6:89d4a7f7588b | 1245 | lcd.printString("Paused", 24, 0); |
avi23 | 8:b2faec20ed8f | 1246 | ///Displays the current score |
avi23 | 6:89d4a7f7588b | 1247 | char buffer[14]; |
avi23 | 6:89d4a7f7588b | 1248 | sprintf(buffer, "Score: %d", score); |
avi23 | 6:89d4a7f7588b | 1249 | lcd.printString(buffer, 0, 1); |
avi23 | 8:b2faec20ed8f | 1250 | ///Displays the no of lives |
avi23 | 6:89d4a7f7588b | 1251 | sprintf(buffer, "Lives: %d", number_of_lives); |
avi23 | 6:89d4a7f7588b | 1252 | lcd.printString(buffer, 0, 2); |
avi23 | 6:89d4a7f7588b | 1253 | lcd.drawLine(0, 23, 83, 23, 2); |
avi23 | 8:b2faec20ed8f | 1254 | ///Prints options on pause menu |
avi23 | 6:89d4a7f7588b | 1255 | lcd.printString("Resume", 5, 3); |
avi23 | 6:89d4a7f7588b | 1256 | lcd.printString("Save", 5, 4); |
avi23 | 6:89d4a7f7588b | 1257 | lcd.printString("Quit", 5, 5); |
avi23 | 6:89d4a7f7588b | 1258 | } |
avi23 | 6:89d4a7f7588b | 1259 | |
avi23 | 6:89d4a7f7588b | 1260 | void MoveCursor(const struct FSMMenus *fsm) |
avi23 | 6:89d4a7f7588b | 1261 | { |
avi23 | 8:b2faec20ed8f | 1262 | ///If the joystick is is pushed down half way clear the cursor and set the next state |
avi23 | 6:89d4a7f7588b | 1263 | if (joystick.GetYValue() < 0.25f) { |
avi23 | 8:b2faec20ed8f | 1264 | ///Clears the cursor |
avi23 | 6:89d4a7f7588b | 1265 | lcd.drawRect(74, cursor_y_pos, 2, 2, 2); |
avi23 | 8:b2faec20ed8f | 1266 | ///Sets the new state |
avi23 | 6:89d4a7f7588b | 1267 | fsm_state = fsm[fsm_state].next_state[0]; |
avi23 | 6:89d4a7f7588b | 1268 | } else if (joystick.GetYValue() > 0.75f) { |
avi23 | 8:b2faec20ed8f | 1269 | ///Clears the cursor |
avi23 | 6:89d4a7f7588b | 1270 | lcd.drawRect(74, cursor_y_pos, 2, 2, 2); |
avi23 | 8:b2faec20ed8f | 1271 | ///Sets the new state |
avi23 | 6:89d4a7f7588b | 1272 | fsm_state = fsm[fsm_state].next_state[1]; |
avi23 | 6:89d4a7f7588b | 1273 | } |
avi23 | 8:b2faec20ed8f | 1274 | } |
avi23 | 8:b2faec20ed8f | 1275 | |
avi23 | 8:b2faec20ed8f | 1276 | void MenuScreen() |
avi23 | 8:b2faec20ed8f | 1277 | { |
avi23 | 8:b2faec20ed8f | 1278 | ///Print the menu text |
avi23 | 8:b2faec20ed8f | 1279 | PrintMenuScreen(); |
avi23 | 8:b2faec20ed8f | 1280 | |
avi23 | 8:b2faec20ed8f | 1281 | while (game_state == menu) { |
avi23 | 8:b2faec20ed8f | 1282 | ///Draws the cursor |
avi23 | 8:b2faec20ed8f | 1283 | 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 | 1284 | lcd.drawRect(74, cursor_y_pos, 2, 2, 1); |
avi23 | 8:b2faec20ed8f | 1285 | |
avi23 | 8:b2faec20ed8f | 1286 | if (g_move_joystick_flag) { |
avi23 | 8:b2faec20ed8f | 1287 | g_move_joystick_flag = false; |
avi23 | 8:b2faec20ed8f | 1288 | |
avi23 | 8:b2faec20ed8f | 1289 | ///Moves the cursor to match the selected option, only if the joystick isn't centred |
avi23 | 8:b2faec20ed8f | 1290 | MoveCursor(fsm_main_menu); |
avi23 | 8:b2faec20ed8f | 1291 | } |
avi23 | 8:b2faec20ed8f | 1292 | |
avi23 | 8:b2faec20ed8f | 1293 | ///If shoot is pressed go to the selected screen |
avi23 | 8:b2faec20ed8f | 1294 | if (g_shoot_pressed_flag) { |
avi23 | 8:b2faec20ed8f | 1295 | g_shoot_pressed_flag = false; |
avi23 | 8:b2faec20ed8f | 1296 | |
avi23 | 8:b2faec20ed8f | 1297 | game_state = fsm_main_menu[fsm_state].output; |
avi23 | 8:b2faec20ed8f | 1298 | |
avi23 | 8:b2faec20ed8f | 1299 | ///If the game state is equal to the game initalise it |
avi23 | 8:b2faec20ed8f | 1300 | if (game_state == game) { |
avi23 | 8:b2faec20ed8f | 1301 | InitaliseGame(); |
avi23 | 8:b2faec20ed8f | 1302 | } |
avi23 | 8:b2faec20ed8f | 1303 | } |
avi23 | 8:b2faec20ed8f | 1304 | |
avi23 | 8:b2faec20ed8f | 1305 | ///Do nothing when the joystick is pressed |
avi23 | 8:b2faec20ed8f | 1306 | if(joystick.get_button_flag()) { |
avi23 | 8:b2faec20ed8f | 1307 | joystick.set_button_flag(0); |
avi23 | 8:b2faec20ed8f | 1308 | } |
avi23 | 8:b2faec20ed8f | 1309 | |
avi23 | 8:b2faec20ed8f | 1310 | lcd.refresh(); |
avi23 | 8:b2faec20ed8f | 1311 | sleep(); |
avi23 | 8:b2faec20ed8f | 1312 | } |
avi23 | 8:b2faec20ed8f | 1313 | } |
avi23 | 8:b2faec20ed8f | 1314 | |
avi23 | 8:b2faec20ed8f | 1315 | void PrintMenuScreen() |
avi23 | 8:b2faec20ed8f | 1316 | { |
avi23 | 8:b2faec20ed8f | 1317 | ///Prints Space invaders, then menu below, then a line underneath |
avi23 | 8:b2faec20ed8f | 1318 | lcd.printString("Space Invaders", 0, 0); |
avi23 | 8:b2faec20ed8f | 1319 | lcd.printString("Menu", 28, 1); |
avi23 | 8:b2faec20ed8f | 1320 | lcd.drawLine(0, 15, 83, 15, 2); |
avi23 | 8:b2faec20ed8f | 1321 | |
avi23 | 8:b2faec20ed8f | 1322 | ///Prints menu options |
avi23 | 8:b2faec20ed8f | 1323 | lcd.printString("New Game", 5, 2); |
avi23 | 8:b2faec20ed8f | 1324 | lcd.printString("Load Game", 5, 3); |
avi23 | 8:b2faec20ed8f | 1325 | lcd.printString("High Scores", 5, 4); |
avi23 | 8:b2faec20ed8f | 1326 | lcd.printString("Settings", 5, 5); |
avi23 | 8:b2faec20ed8f | 1327 | } |
avi23 | 8:b2faec20ed8f | 1328 | |
avi23 | 8:b2faec20ed8f | 1329 | void AttemptToSpawnUFO() |
avi23 | 8:b2faec20ed8f | 1330 | { |
avi23 | 8:b2faec20ed8f | 1331 | ///1/8 chance of UFO spawning if it hasn't already |
avi23 | 8:b2faec20ed8f | 1332 | if (!ufo_on_screen && (rand() % 8 == 1) && down_count > 1 && no_of_alive_invaders > 3) { |
avi23 | 8:b2faec20ed8f | 1333 | ///Marks the UFO as on the screen and sets its position and direction |
avi23 | 8:b2faec20ed8f | 1334 | ufo_on_screen = true; |
avi23 | 8:b2faec20ed8f | 1335 | ufo_direction = (rand() % 2); |
avi23 | 8:b2faec20ed8f | 1336 | if (ufo_direction == RIGHT) { |
avi23 | 8:b2faec20ed8f | 1337 | ufo_x_pos = -14; |
avi23 | 8:b2faec20ed8f | 1338 | } else { |
avi23 | 8:b2faec20ed8f | 1339 | ufo_x_pos = 83; |
avi23 | 8:b2faec20ed8f | 1340 | } |
avi23 | 8:b2faec20ed8f | 1341 | |
avi23 | 8:b2faec20ed8f | 1342 | ///Attachs the move UFO ticker |
avi23 | 8:b2faec20ed8f | 1343 | move_ufo.attach(&move_ufo_isr, 0.1); |
avi23 | 8:b2faec20ed8f | 1344 | } |
avi23 | 8:b2faec20ed8f | 1345 | } |
avi23 | 8:b2faec20ed8f | 1346 | |
avi23 | 8:b2faec20ed8f | 1347 | void ClearUFO() |
avi23 | 8:b2faec20ed8f | 1348 | { |
avi23 | 8:b2faec20ed8f | 1349 | ///Clears the UFO |
avi23 | 8:b2faec20ed8f | 1350 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 1351 | for (int row = 0; row < 5; ++row) { |
avi23 | 8:b2faec20ed8f | 1352 | ///Only clear the pixel in the buffer if it is within bounds |
avi23 | 8:b2faec20ed8f | 1353 | if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) { |
avi23 | 8:b2faec20ed8f | 1354 | if (ufo_bitmap[row][col]) { |
avi23 | 8:b2faec20ed8f | 1355 | screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = empty_pixel; |
avi23 | 8:b2faec20ed8f | 1356 | } |
avi23 | 8:b2faec20ed8f | 1357 | } |
avi23 | 8:b2faec20ed8f | 1358 | } |
avi23 | 8:b2faec20ed8f | 1359 | } |
avi23 | 8:b2faec20ed8f | 1360 | } |
avi23 | 8:b2faec20ed8f | 1361 | |
avi23 | 8:b2faec20ed8f | 1362 | void DrawUFO() |
avi23 | 8:b2faec20ed8f | 1363 | { |
avi23 | 8:b2faec20ed8f | 1364 | ///Checks if the ufo can be within the screen bounds |
avi23 | 8:b2faec20ed8f | 1365 | ///If it is, push the ufo to the screen buffer |
avi23 | 8:b2faec20ed8f | 1366 | if (ufo_x_pos > -14 && ufo_x_pos < 84) { |
avi23 | 8:b2faec20ed8f | 1367 | for (int col = 0; col < 14; ++col) { |
avi23 | 8:b2faec20ed8f | 1368 | for (int row = 0; row < 5; ++row) { |
avi23 | 8:b2faec20ed8f | 1369 | ///Only clear the pixel in the buffer if it is within bounds |
avi23 | 8:b2faec20ed8f | 1370 | if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) { |
avi23 | 8:b2faec20ed8f | 1371 | if (ufo_bitmap[row][col]) { |
avi23 | 8:b2faec20ed8f | 1372 | screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = ufo_pixel; |
avi23 | 8:b2faec20ed8f | 1373 | } |
avi23 | 8:b2faec20ed8f | 1374 | } |
avi23 | 8:b2faec20ed8f | 1375 | } |
avi23 | 8:b2faec20ed8f | 1376 | } |
avi23 | 8:b2faec20ed8f | 1377 | } else { |
avi23 | 8:b2faec20ed8f | 1378 | ///Otherwise mark it as not on the screen and detach the ticker |
avi23 | 8:b2faec20ed8f | 1379 | ufo_on_screen = false; |
avi23 | 8:b2faec20ed8f | 1380 | move_ufo.detach(); |
avi23 | 8:b2faec20ed8f | 1381 | } |
avi23 | 0:427469992efe | 1382 | } |