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

Dependencies:   Joystick N5110 SDFileSystem mbed

Committer:
avi23
Date:
Thu Apr 28 14:14:54 2016 +0000
Revision:
6:89d4a7f7588b
Parent:
5:34855f712350
Child:
7:babc367a3333
Menu Cursors work

Who changed what in which revision?

UserRevisionLine numberNew contents of line
avi23 1:b300d052d549 1 /*
avi23 1:b300d052d549 2 Space Invaders - Avinash Patel 200860407
avi23 1:b300d052d549 3
avi23 1:b300d052d549 4 Week 19 - Set up joystick class
avi23 1:b300d052d549 5 Week 20 - Changed to space invaders as constrained too much by screen resolution
avi23 1:b300d052d549 6 - Core cannon is drawn and can move, enemies are visible and they switch between states every second
avi23 2:d34c95990605 7 Week 21 - Begun to set up barriers
avi23 5:34855f712350 8 Easter - Barriers work, invader and player can shoot. Begun setting up menus
avi23 1:b300d052d549 9 */
avi23 0:427469992efe 10 #include "mbed.h"
avi23 0:427469992efe 11 #include "N5110.h"
avi23 0:427469992efe 12
avi23 2:d34c95990605 13 //Direction invaders are travelling
avi23 2:d34c95990605 14 #define LEFT 0
avi23 2:d34c95990605 15 #define RIGHT 1
avi23 2:d34c95990605 16
avi23 0:427469992efe 17 //Joystick Class
avi23 0:427469992efe 18 class Joystick
avi23 0:427469992efe 19 {
avi23 0:427469992efe 20 public:
avi23 5:34855f712350 21 //Constructor
avi23 0:427469992efe 22 Joystick(PinName x_axis_pin, PinName y_axis_pin, PinName button_pin) {
avi23 5:34855f712350 23 //Dynamically allocates the pins and button debounce ticker
avi23 0:427469992efe 24 x_axis_ = new AnalogIn(x_axis_pin);
avi23 0:427469992efe 25 y_axis_ = new AnalogIn(y_axis_pin);
avi23 0:427469992efe 26 button_ = new InterruptIn(button_pin);
avi23 5:34855f712350 27 button_debounce_ = new Timeout();
avi23 5:34855f712350 28 }
avi23 5:34855f712350 29
avi23 5:34855f712350 30 //Deconstructor
avi23 5:34855f712350 31 ~Joystick() {
avi23 5:34855f712350 32 //Clears all dynamically allocated memory
avi23 5:34855f712350 33 delete x_axis_;
avi23 5:34855f712350 34 delete y_axis_;
avi23 5:34855f712350 35 delete button_;
avi23 5:34855f712350 36 delete button_debounce_;
avi23 0:427469992efe 37 }
avi23 0:427469992efe 38
avi23 0:427469992efe 39 //Initalises the Joystick
avi23 0:427469992efe 40 //Sets up the ISRs and grabs the offsets for each axis
avi23 0:427469992efe 41 void init() {
avi23 0:427469992efe 42 //Sets up the button ISR
avi23 5:34855f712350 43 button_->mode(PullDown);
avi23 5:34855f712350 44 button_->rise(this, &Joystick::button_isr);
avi23 0:427469992efe 45
avi23 0:427469992efe 46 //Initalises the vairables and flags
avi23 0:427469992efe 47 x_offset_ = 0;
avi23 0:427469992efe 48 y_offset_ = 0;
avi23 5:34855f712350 49 g_button_flag_ = false;
avi23 5:34855f712350 50 g_button_debounce_flag_ = false;
avi23 0:427469992efe 51
avi23 0:427469992efe 52 //Samples the joystick 5 times and takes an average to get the offset
avi23 0:427469992efe 53 float x_sum = 0;
avi23 0:427469992efe 54 float y_sum = 0;
avi23 0:427469992efe 55
avi23 5:34855f712350 56 for (int i = 0; i < 5; ++i) {
avi23 0:427469992efe 57 x_sum += x_axis_->read();
avi23 0:427469992efe 58 y_sum += y_axis_->read();
avi23 0:427469992efe 59 }
avi23 0:427469992efe 60
avi23 0:427469992efe 61 x_offset_ = 0.5f - x_sum/5.0f;
avi23 0:427469992efe 62 y_offset_ = 0.5f - y_sum/5.0f;
avi23 0:427469992efe 63 }
avi23 0:427469992efe 64
avi23 0:427469992efe 65 //Take 5 readings and returns the average measurement, accounting for joystick offset x and y values
avi23 0:427469992efe 66 float GetXValue() {
avi23 0:427469992efe 67
avi23 0:427469992efe 68 float x_sum = 0;
avi23 0:427469992efe 69
avi23 5:34855f712350 70 for (int i = 0; i < 5; ++i) {
avi23 0:427469992efe 71 x_sum += x_axis_->read();
avi23 0:427469992efe 72 }
avi23 0:427469992efe 73
avi23 0:427469992efe 74 float x_value = x_sum/5.0f + x_offset_;
avi23 0:427469992efe 75
avi23 0:427469992efe 76 //Caps the value for the POT between 0 and 1
avi23 0:427469992efe 77 if (x_value < 0.0f) {
avi23 0:427469992efe 78 return 0;
avi23 0:427469992efe 79 } else if (x_value > 1.0f) {
avi23 0:427469992efe 80 return 1;
avi23 0:427469992efe 81 } else {
avi23 0:427469992efe 82 return x_value;
avi23 0:427469992efe 83 }
avi23 0:427469992efe 84 }
avi23 0:427469992efe 85
avi23 0:427469992efe 86 float GetYValue() {
avi23 0:427469992efe 87
avi23 0:427469992efe 88 float y_sum = 0;
avi23 0:427469992efe 89
avi23 5:34855f712350 90 for (int i = 0; i < 5; ++i) {
avi23 0:427469992efe 91 y_sum += y_axis_->read();
avi23 0:427469992efe 92 }
avi23 0:427469992efe 93
avi23 0:427469992efe 94 float y_value = y_sum/5.0f + y_offset_;
avi23 0:427469992efe 95
avi23 0:427469992efe 96 //Caps the value for the POT between 0 and 1
avi23 0:427469992efe 97 if (y_value < 0.0f) {
avi23 0:427469992efe 98 return 0;
avi23 0:427469992efe 99 } else if (y_value > 1.0f) {
avi23 0:427469992efe 100 return 1;
avi23 0:427469992efe 101 } else {
avi23 0:427469992efe 102 return y_value;
avi23 0:427469992efe 103 }
avi23 0:427469992efe 104 }
avi23 0:427469992efe 105
avi23 0:427469992efe 106 //Getter and setters for flags
avi23 0:427469992efe 107 int get_button_flag() {
avi23 0:427469992efe 108 return g_button_flag_;
avi23 0:427469992efe 109 }
avi23 0:427469992efe 110
avi23 0:427469992efe 111 void set_button_flag(int value) {
avi23 0:427469992efe 112 g_button_flag_ = value;
avi23 0:427469992efe 113 }
avi23 0:427469992efe 114
avi23 0:427469992efe 115 private:
avi23 0:427469992efe 116 //Button ISR Method
avi23 0:427469992efe 117 void button_isr() {
avi23 5:34855f712350 118 if (!g_button_debounce_flag_) {
avi23 5:34855f712350 119 g_button_flag_ = true;
avi23 5:34855f712350 120 g_button_debounce_flag_ = true;
avi23 5:34855f712350 121
avi23 5:34855f712350 122 //Sets up the debounce ticker
avi23 5:34855f712350 123 button_debounce_->attach(this, &Joystick::button_debounce_isr, 0.2);
avi23 5:34855f712350 124 }
avi23 5:34855f712350 125 }
avi23 5:34855f712350 126
avi23 5:34855f712350 127 //Button debounce ISR method
avi23 5:34855f712350 128 void button_debounce_isr() {
avi23 5:34855f712350 129 g_button_debounce_flag_ = false;
avi23 0:427469992efe 130 }
avi23 0:427469992efe 131
avi23 0:427469992efe 132 private:
avi23 0:427469992efe 133 //Pin inputs
avi23 0:427469992efe 134 AnalogIn* x_axis_;
avi23 0:427469992efe 135 AnalogIn* y_axis_;
avi23 0:427469992efe 136 InterruptIn* button_;
avi23 0:427469992efe 137
avi23 6:89d4a7f7588b 138 //Timeout to prevent joystick button bounce
avi23 5:34855f712350 139 Timeout* button_debounce_;
avi23 5:34855f712350 140
avi23 0:427469992efe 141 //Stores X and Y offsets
avi23 0:427469992efe 142 float x_offset_;
avi23 0:427469992efe 143 float y_offset_;
avi23 0:427469992efe 144
avi23 0:427469992efe 145 //Stores interrupt flags
avi23 5:34855f712350 146 volatile bool g_button_flag_;
avi23 5:34855f712350 147 volatile bool g_button_debounce_flag_;
avi23 0:427469992efe 148 };
avi23 0:427469992efe 149
avi23 0:427469992efe 150 // K64F on-board LEDs
avi23 0:427469992efe 151 DigitalOut r_led(LED_RED);
avi23 0:427469992efe 152 DigitalOut g_led(LED_GREEN);
avi23 0:427469992efe 153 DigitalOut b_led(LED_BLUE);
avi23 0:427469992efe 154
avi23 0:427469992efe 155 // K64F on-board switches
avi23 0:427469992efe 156 InterruptIn sw2(SW2);
avi23 0:427469992efe 157 InterruptIn sw3(SW3);
avi23 0:427469992efe 158
avi23 0:427469992efe 159 // UART connection for PC
avi23 0:427469992efe 160 Serial pc(USBTX,USBRX);
avi23 0:427469992efe 161
avi23 0:427469992efe 162 //Joystick
avi23 5:34855f712350 163 Joystick joystick(PTB3, PTB2, PTB11);
avi23 2:d34c95990605 164
avi23 2:d34c95990605 165 //Shoot button
avi23 2:d34c95990605 166 InterruptIn shoot_button(PTB18);
avi23 0:427469992efe 167
avi23 0:427469992efe 168 //LCD object
avi23 0:427469992efe 169 // VCC, SCE, RST, D/C, MOSI, SCLK, LED
avi23 0:427469992efe 170 N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);
avi23 2:d34c95990605 171
avi23 5:34855f712350 172 //Tickers
avi23 5:34855f712350 173 Ticker update_screen;
avi23 5:34855f712350 174 Ticker move_joystick;
avi23 5:34855f712350 175 Ticker move_cannon_missile;
avi23 5:34855f712350 176 Ticker move_enemies;
avi23 5:34855f712350 177 Ticker move_invader_normal_missile[2];
avi23 5:34855f712350 178
avi23 5:34855f712350 179 //Timeout
avi23 5:34855f712350 180 Timeout joystick_cursor_regulator; //Stops the cursor from jumping
avi23 6:89d4a7f7588b 181 Timeout shoot_button_debounce; //Stops the cannon from firing when transitioning from a menu to the game
avi23 5:34855f712350 182
avi23 5:34855f712350 183 //Buffer holding pixel data of screen with point representations
avi23 5:34855f712350 184 int screen_buffer[84][48];
avi23 4:a99953ef9e42 185 const int empty_pixel = 0;
avi23 4:a99953ef9e42 186 const int cannon_pixel = 1;
avi23 4:a99953ef9e42 187 const int first_barrier_pixel = 2;
avi23 4:a99953ef9e42 188 const int first_large_invader_pixel = 5;
avi23 4:a99953ef9e42 189 const int first_medium_invader_pixel = 10;
avi23 4:a99953ef9e42 190 const int first_small_invader_pixel = 15;
avi23 4:a99953ef9e42 191 const int ufo_pixel = 20;
avi23 5:34855f712350 192 const int cannon_missile_pixel = 21;
avi23 5:34855f712350 193 const int invader_normal_missile_pixel = 22;
avi23 0:427469992efe 194
avi23 5:34855f712350 195 //Booleans
avi23 5:34855f712350 196 //Invader related bools
avi23 5:34855f712350 197 bool invaders_in_state2 = true;
avi23 5:34855f712350 198 bool invader_direction = RIGHT;
avi23 5:34855f712350 199 //Cannon missile bool
avi23 5:34855f712350 200 bool cannon_missile_on_screen = false;
avi23 5:34855f712350 201
avi23 5:34855f712350 202 //Integers
avi23 5:34855f712350 203 int score = 0; //Stores the score
avi23 5:34855f712350 204 int fsm_state = 0; //Stores the state for menu fsm's
avi23 5:34855f712350 205 int cursor_y_pos = 0; //Stores the cursor position
avi23 5:34855f712350 206 //Cannon related integers
avi23 6:89d4a7f7588b 207 int number_of_lives = 3;
avi23 1:b300d052d549 208 int cannon_xpos = 24;
avi23 1:b300d052d549 209 const int cannon_ypos = 43;
avi23 5:34855f712350 210 //Cannon missile related integers
avi23 5:34855f712350 211 int cannon_missile_x_pos = 28;
avi23 5:34855f712350 212 int cannon_missile_y_pos = 40;
avi23 6:89d4a7f7588b 213 //Invader related integers
avi23 5:34855f712350 214 int no_of_alive_invaders = 15;
avi23 5:34855f712350 215 //Invader missile related integers
avi23 5:34855f712350 216 int invader_strong_missile_x_pos;
avi23 5:34855f712350 217 int invader_strong_missile_y_pos;
avi23 5:34855f712350 218
avi23 5:34855f712350 219 //Floats
avi23 5:34855f712350 220 float ticker_period = 1; //Stores the period of the invader move ticker
avi23 5:34855f712350 221
avi23 5:34855f712350 222 //Enums
avi23 5:34855f712350 223 enum Status {dead, dying, alive}; //Contains the status of invaders
avi23 5:34855f712350 224 enum Invader {small, medium, large, none}; //Contains the type of invader passed into
avi23 5:34855f712350 225 //Contains the current state of the game
avi23 6:89d4a7f7588b 226 enum GameState {menu, game, paused, save, load, scores, settings};
avi23 5:34855f712350 227 GameState game_state = menu;
avi23 5:34855f712350 228
avi23 5:34855f712350 229 //Bit-maps
avi23 5:34855f712350 230 //Cannon bit-map
avi23 1:b300d052d549 231 const bool cannon_bitmap[5][9] = {
avi23 0:427469992efe 232 {0, 0, 0, 0, 1, 0, 0, 0, 0},
avi23 0:427469992efe 233 {0, 0, 0, 1, 1, 1, 0, 0, 0},
avi23 0:427469992efe 234 {0, 1, 1, 1, 1, 1, 1, 1, 0},
avi23 0:427469992efe 235 {1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 0:427469992efe 236 {1, 1, 1, 1, 1, 1, 1, 1, 1}
avi23 0:427469992efe 237 };
avi23 1:b300d052d549 238 //Bitmaps for small invaders
avi23 5:34855f712350 239 const bool small_invader_bitmap_1[6][8] = { //First state
avi23 0:427469992efe 240 {0, 0, 0, 1, 1, 0, 0, 0},
avi23 0:427469992efe 241 {0, 1, 1, 1, 1, 1, 1, 0},
avi23 0:427469992efe 242 {1, 1, 0, 1, 1, 0, 1, 1},
avi23 0:427469992efe 243 {1, 1, 1, 1, 1, 1, 1, 1},
avi23 0:427469992efe 244 {0, 1, 0, 1, 1, 0, 1, 0},
avi23 0:427469992efe 245 {1, 0, 1, 0, 0, 1, 0, 1}
avi23 0:427469992efe 246 };
avi23 5:34855f712350 247 const bool small_invader_bitmap_2[6][8] = { //Second state
avi23 0:427469992efe 248 {0, 0, 0, 1, 1, 0, 0, 0},
avi23 0:427469992efe 249 {0, 1, 1, 1, 1, 1, 1, 0},
avi23 0:427469992efe 250 {1, 1, 0, 1, 1, 0, 1, 1},
avi23 0:427469992efe 251 {1, 1, 1, 1, 1, 1, 1, 1},
avi23 0:427469992efe 252 {1, 0, 0, 0, 0, 0, 0, 1},
avi23 0:427469992efe 253 {0, 1, 0, 0, 0, 0, 1, 0}
avi23 0:427469992efe 254 };
avi23 1:b300d052d549 255 //Bitmaps for medium invaders
avi23 5:34855f712350 256 const bool medium_invader_bitmap_1[6][10] = { //First state
avi23 1:b300d052d549 257 {1, 0, 0, 1, 0, 0, 1, 0, 0, 1},
avi23 1:b300d052d549 258 {1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
avi23 1:b300d052d549 259 {1, 1, 1, 0, 1, 1, 0, 1, 1, 1},
avi23 1:b300d052d549 260 {0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
avi23 1:b300d052d549 261 {0, 0, 1, 0, 0, 0, 0, 1, 0, 0},
avi23 1:b300d052d549 262 {0, 1, 0, 0, 0, 0, 0, 0, 1, 0}
avi23 1:b300d052d549 263 };
avi23 5:34855f712350 264 const bool medium_invader_bitmap_2[6][10] = { //Second state
avi23 1:b300d052d549 265 {0, 0, 0, 1, 0, 0, 1, 0, 0, 0},
avi23 1:b300d052d549 266 {0, 0, 1, 1, 1, 1, 1, 1, 0, 0},
avi23 1:b300d052d549 267 {0, 1, 1, 0, 1, 1, 0, 1, 1, 0},
avi23 1:b300d052d549 268 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 1:b300d052d549 269 {1, 0, 1, 0, 0, 0, 0, 1, 0, 1},
avi23 1:b300d052d549 270 {0, 0, 0, 1, 1, 1, 1, 0, 0, 0}
avi23 1:b300d052d549 271 };
avi23 1:b300d052d549 272 //Bitmaps for large invaders
avi23 5:34855f712350 273 const bool large_invader_bitmap_1[6][12] = { //First state
avi23 2:d34c95990605 274 {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
avi23 1:b300d052d549 275 {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
avi23 1:b300d052d549 276 {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
avi23 1:b300d052d549 277 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 1:b300d052d549 278 {0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0},
avi23 1:b300d052d549 279 {0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0}
avi23 1:b300d052d549 280 };
avi23 5:34855f712350 281 const bool large_invader_bitmap_2[6][12] = { //Second state
avi23 2:d34c95990605 282 {0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
avi23 1:b300d052d549 283 {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
avi23 1:b300d052d549 284 {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
avi23 1:b300d052d549 285 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 1:b300d052d549 286 {0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0},
avi23 1:b300d052d549 287 {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
avi23 1:b300d052d549 288 };
avi23 5:34855f712350 289 //Normal invader missile bitmap
avi23 5:34855f712350 290 const bool invader_normal_missile_bitmap[4][3] = {
avi23 5:34855f712350 291 {0, 1, 0},
avi23 5:34855f712350 292 {1, 1, 1},
avi23 5:34855f712350 293 {0, 1, 0},
avi23 5:34855f712350 294 {0, 1, 0}
avi23 5:34855f712350 295 };
avi23 5:34855f712350 296 //Strong invader missile bitmap
avi23 5:34855f712350 297 const bool invader_strong_missile_bitmap_1[4][3] = { //First state
avi23 5:34855f712350 298 {0, 0, 1},
avi23 5:34855f712350 299 {0, 1, 0},
avi23 5:34855f712350 300 {1, 0, 0},
avi23 5:34855f712350 301 {0, 1, 0}
avi23 5:34855f712350 302 };
avi23 5:34855f712350 303 const bool invader_strong_missile_bitmap_2[4][3] = { //Second state
avi23 5:34855f712350 304 {0, 1, 0},
avi23 5:34855f712350 305 {1, 0, 0},
avi23 5:34855f712350 306 {0, 1, 0},
avi23 5:34855f712350 307 {0, 1, 1}
avi23 5:34855f712350 308 };
avi23 5:34855f712350 309 //Barrier bitmap
avi23 2:d34c95990605 310 const bool barrier_bitmap[8][14] = {
avi23 2:d34c95990605 311 {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
avi23 2:d34c95990605 312 {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
avi23 2:d34c95990605 313 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 2:d34c95990605 314 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 2:d34c95990605 315 {1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1},
avi23 2:d34c95990605 316 {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
avi23 2:d34c95990605 317 {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
avi23 2:d34c95990605 318 {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
avi23 2:d34c95990605 319 };
avi23 5:34855f712350 320 //Cannon barrier damage bitmap
avi23 5:34855f712350 321 const bool barrier_cannon_missile_damage_bitmap[3][3] = {
avi23 5:34855f712350 322 {0, 1, 0},
avi23 5:34855f712350 323 {1, 0, 0},
avi23 5:34855f712350 324 {1, 0, 1}
avi23 5:34855f712350 325 };
avi23 5:34855f712350 326 //Normal invader barrier damage bitmap
avi23 5:34855f712350 327 const bool barrier_invader_normal_missile_damage_bitmap[2][3] = {
avi23 5:34855f712350 328 {1, 0, 1},
avi23 5:34855f712350 329 {0, 1, 0}
avi23 5:34855f712350 330 };
avi23 5:34855f712350 331 //UFO Bitmap
avi23 2:d34c95990605 332 const bool ufo_bitmap[5][14] = {
avi23 2:d34c95990605 333 {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
avi23 2:d34c95990605 334 {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
avi23 2:d34c95990605 335 {0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0},
avi23 2:d34c95990605 336 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
avi23 2:d34c95990605 337 {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}
avi23 2:d34c95990605 338 };
avi23 2:d34c95990605 339
avi23 5:34855f712350 340 //Structs
avi23 5:34855f712350 341 //Contains invader data
avi23 5:34855f712350 342 struct Invaders {
avi23 5:34855f712350 343 int x_pos;
avi23 5:34855f712350 344 int y_pos;
avi23 5:34855f712350 345 enum Status status;
avi23 5:34855f712350 346 } small_invader[5], medium_invader[5], large_invader[5]; //Five of each invader
avi23 5:34855f712350 347 //Contains data for Invader normal missiles
avi23 5:34855f712350 348 struct InvaderNormalMissiles {
avi23 5:34855f712350 349 int x_pos;
avi23 5:34855f712350 350 int y_pos;
avi23 5:34855f712350 351 bool fired;
avi23 5:34855f712350 352 } invader_normal_missile[2];
avi23 5:34855f712350 353 //Contains data for barriers
avi23 5:34855f712350 354 struct Barriers {
avi23 5:34855f712350 355 int x_pos;
avi23 5:34855f712350 356 int y_pos;
avi23 5:34855f712350 357 bool before_bitmap[8][14];
avi23 5:34855f712350 358 bool after_bitmap[8][14];
avi23 5:34855f712350 359 } barrier[3];
avi23 6:89d4a7f7588b 360 //FSM for menus
avi23 6:89d4a7f7588b 361 struct FSMMenus {
avi23 5:34855f712350 362 GameState output;
avi23 5:34855f712350 363 int next_state[2];
avi23 5:34855f712350 364 };
avi23 6:89d4a7f7588b 365 FSMMenus fsm_main_menu[4] = {
avi23 6:89d4a7f7588b 366 {game, {1, 3}},
avi23 6:89d4a7f7588b 367 {load, {2, 0}},
avi23 6:89d4a7f7588b 368 {scores, {3, 1}},
avi23 6:89d4a7f7588b 369 {settings, {0, 2}}
avi23 6:89d4a7f7588b 370 };
avi23 6:89d4a7f7588b 371 FSMMenus fsm_paused[3] = { //Pause menu FSM
avi23 5:34855f712350 372 {game, {1, 2}},
avi23 5:34855f712350 373 {save, {2, 0}},
avi23 5:34855f712350 374 {menu, {0, 1}}
avi23 5:34855f712350 375 };
avi23 0:427469992efe 376
avi23 0:427469992efe 377 //ISR Flags
avi23 2:d34c95990605 378 volatile bool g_update_screen_flag = true;
avi23 5:34855f712350 379 volatile bool g_move_joystick_flag = true;
avi23 5:34855f712350 380 volatile bool g_move_enemies_flag = true;
avi23 2:d34c95990605 381 volatile bool g_shoot_pressed_flag = false;
avi23 5:34855f712350 382 volatile bool g_move_cannon_missile_flag = false;
avi23 5:34855f712350 383 volatile bool g_move_invader_normal_missile_flag[2] = {false, false};
avi23 5:34855f712350 384 volatile bool g_cannon_hit_flag = false;
avi23 5:34855f712350 385 volatile bool g_joystick_cursor_regulator_flag = false;
avi23 6:89d4a7f7588b 386 volatile bool g_shoot_button_debounce_flag = false;
avi23 0:427469992efe 387
avi23 0:427469992efe 388 // function prototypes
avi23 0:427469992efe 389 // error function hangs flashing an LED
avi23 0:427469992efe 390 void error();
avi23 0:427469992efe 391 // setup serial port
avi23 0:427469992efe 392 void init_serial();
avi23 0:427469992efe 393 // set-up the on-board LEDs and switches
avi23 0:427469992efe 394 void init_K64F();
avi23 2:d34c95990605 395 //Init shoot button
avi23 2:d34c95990605 396 void init_shoot();
avi23 5:34855f712350 397 //Init Random Number Generator
avi23 5:34855f712350 398 void init_rng();
avi23 0:427469992efe 399 // Added functions
avi23 5:34855f712350 400 void InitaliseGame();
avi23 5:34855f712350 401 void Game();
avi23 5:34855f712350 402 void UpdateScreen();
avi23 2:d34c95990605 403 void MoveCannon();
avi23 0:427469992efe 404 void InitSmallInvaders();
avi23 2:d34c95990605 405 void ClearSmallInvaders();
avi23 5:34855f712350 406 void ClearSingleSmallInvader(int invader_no);
avi23 0:427469992efe 407 void DrawSmallInvaders();
avi23 5:34855f712350 408 void DrawSingleSmallInvader(int invader_no);
avi23 5:34855f712350 409 void InitMediumInvaders();
avi23 2:d34c95990605 410 void ClearMediumInvaders();
avi23 5:34855f712350 411 void ClearSingleMediumInvader(int invader_no);
avi23 1:b300d052d549 412 void DrawMediumInvaders();
avi23 5:34855f712350 413 void DrawSingleMediumInvader(int invader_no);
avi23 1:b300d052d549 414 void InitLargeInvaders();
avi23 5:34855f712350 415 void ClearLargeInvaders();
avi23 5:34855f712350 416 void ClearSingleLargeInvader(int invader_no);
avi23 1:b300d052d549 417 void DrawLargeInvaders();
avi23 5:34855f712350 418 void DrawSingleLargeInvader(int invader_no);
avi23 2:d34c95990605 419 void InitBarriers();
avi23 2:d34c95990605 420 void DrawBarriers();
avi23 5:34855f712350 421 void MoveInvaderXPositions();
avi23 5:34855f712350 422 int CalculateInvaderLeftLimit();
avi23 5:34855f712350 423 int CalculateInvaderRightLimit();
avi23 5:34855f712350 424 void MoveInvadersLeft(int limit);
avi23 5:34855f712350 425 void MoveInvadersRight(int limit);
avi23 5:34855f712350 426 void MoveInvaderYPositions(bool new_direction);
avi23 5:34855f712350 427 Invader CalculateInvaderYLimit();
avi23 5:34855f712350 428 Invader LowestInvaderInColumn(int column);
avi23 5:34855f712350 429 void FireCannonMissile();
avi23 5:34855f712350 430 void MoveCannonMissile();
avi23 5:34855f712350 431 void CollisionDetectionCannonMissile();
avi23 5:34855f712350 432 int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5]);
avi23 5:34855f712350 433 void CannonMissileHitBarrier(int first_pixel, int row);
avi23 5:34855f712350 434 void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile));
avi23 5:34855f712350 435 void AttemptToFireInvaderNormalMissiles();
avi23 5:34855f712350 436 void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader));
avi23 5:34855f712350 437 void MoveInvaderNormalMissile(int missile_no);
avi23 5:34855f712350 438 void CollisionDetectionInvaderNormalMissile(int missile_no);
avi23 5:34855f712350 439 void DetachTickers();
avi23 5:34855f712350 440 void AttachTickers();
avi23 6:89d4a7f7588b 441 //Pause Menu Functions
avi23 6:89d4a7f7588b 442 void PauseScreen();
avi23 6:89d4a7f7588b 443 void PrintPauseScreen();
avi23 6:89d4a7f7588b 444 void MoveCursor(const struct FSMMenus *fsm);
avi23 2:d34c95990605 445 //void InitUFO();
avi23 2:d34c95990605 446 void DrawUFO();
avi23 0:427469992efe 447 //ISR's
avi23 2:d34c95990605 448 void update_screen_isr();
avi23 5:34855f712350 449 void move_joystick_isr();
avi23 0:427469992efe 450 void move_enemies_isr();
avi23 2:d34c95990605 451 void shoot_pressed_isr();
avi23 5:34855f712350 452 void move_cannon_missile_isr();
avi23 5:34855f712350 453 void cannon_hit_isr();
avi23 5:34855f712350 454 void joystick_cursor_regulator_isr();
avi23 6:89d4a7f7588b 455 void shoot_button_debounce_isr();
avi23 5:34855f712350 456 //Function pointer to move invader normal missile isr
avi23 5:34855f712350 457 void (*move_invader_normal_missile_isr[2])();
avi23 5:34855f712350 458 void move_invader_normal_missile_0_isr();
avi23 5:34855f712350 459 void move_invader_normal_missile_1_isr();
avi23 0:427469992efe 460
avi23 5:34855f712350 461 int row_no = 5;
avi23 5:34855f712350 462 int col_no = 14;
avi23 0:427469992efe 463
avi23 0:427469992efe 464 int main()
avi23 0:427469992efe 465 {
avi23 5:34855f712350 466 //Wait for 2 seconds to allow power to settle
avi23 5:34855f712350 467 wait(1);
avi23 0:427469992efe 468 //Initalises the board and perhiperals
avi23 0:427469992efe 469 init_K64F();
avi23 0:427469992efe 470 init_serial();
avi23 2:d34c95990605 471 init_shoot();
avi23 5:34855f712350 472 init_rng();
avi23 5:34855f712350 473 joystick.init();
avi23 0:427469992efe 474 lcd.init();
avi23 0:427469992efe 475 lcd.clear();
avi23 0:427469992efe 476
avi23 5:34855f712350 477 //Configures the function pointer for the invaders normal missile
avi23 5:34855f712350 478 move_invader_normal_missile_isr[0] = &move_invader_normal_missile_0_isr;
avi23 5:34855f712350 479 move_invader_normal_missile_isr[1] = &move_invader_normal_missile_1_isr;
avi23 0:427469992efe 480
avi23 5:34855f712350 481 //Samples joystick every 0.05 second
avi23 5:34855f712350 482 move_joystick.attach(&move_joystick_isr, 0.05);
avi23 2:d34c95990605 483
avi23 6:89d4a7f7588b 484
avi23 6:89d4a7f7588b 485
avi23 2:d34c95990605 486 while (true) {
avi23 5:34855f712350 487 if (game_state == menu) { //Menu screen
avi23 2:d34c95990605 488 lcd.clear();
avi23 6:89d4a7f7588b 489 fsm_state = 0; //Sets the fsm state to 0
avi23 6:89d4a7f7588b 490 while (game_state == menu) {
avi23 6:89d4a7f7588b 491 lcd.printString("Space Invaders", 0, 0);
avi23 6:89d4a7f7588b 492 lcd.printString("Menu", 28, 1);
avi23 6:89d4a7f7588b 493 lcd.drawLine(0, 15, 83, 15, 2);
avi23 6:89d4a7f7588b 494
avi23 6:89d4a7f7588b 495 lcd.printString("New Game", 5, 2);
avi23 6:89d4a7f7588b 496 lcd.printString("Load Game", 5, 3);
avi23 6:89d4a7f7588b 497 lcd.printString("High Scores", 5, 4);
avi23 6:89d4a7f7588b 498 lcd.printString("Settings", 5, 5);
avi23 6:89d4a7f7588b 499
avi23 6:89d4a7f7588b 500 //Draws the cursor
avi23 6:89d4a7f7588b 501 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 6:89d4a7f7588b 502 lcd.drawRect(74, cursor_y_pos, 2, 2, 1);
avi23 6:89d4a7f7588b 503
avi23 6:89d4a7f7588b 504 if (g_move_joystick_flag) {
avi23 6:89d4a7f7588b 505 g_move_joystick_flag = false;
avi23 6:89d4a7f7588b 506
avi23 6:89d4a7f7588b 507 //Moves the cursor to match the selected option, only if the joystick isn't centred
avi23 6:89d4a7f7588b 508 MoveCursor(fsm_main_menu);
avi23 6:89d4a7f7588b 509 }
avi23 6:89d4a7f7588b 510
avi23 6:89d4a7f7588b 511 if (g_shoot_pressed_flag) {
avi23 6:89d4a7f7588b 512 g_shoot_pressed_flag = false;
avi23 6:89d4a7f7588b 513
avi23 6:89d4a7f7588b 514 game_state = fsm_main_menu[fsm_state].output;
avi23 2:d34c95990605 515
avi23 6:89d4a7f7588b 516 //If the game state is equal to the game initalise it
avi23 6:89d4a7f7588b 517 if (game_state == game) {
avi23 6:89d4a7f7588b 518 //Clears the screen buffer and runs init functions
avi23 6:89d4a7f7588b 519 memset(screen_buffer, 0, sizeof(screen_buffer));
avi23 6:89d4a7f7588b 520 no_of_alive_invaders = 15;
avi23 6:89d4a7f7588b 521 score = 0;
avi23 6:89d4a7f7588b 522 number_of_lives = 3;
avi23 6:89d4a7f7588b 523 InitSmallInvaders();
avi23 6:89d4a7f7588b 524 InitMediumInvaders();
avi23 6:89d4a7f7588b 525 InitLargeInvaders();
avi23 6:89d4a7f7588b 526 InitBarriers();
avi23 6:89d4a7f7588b 527 //Sets the flags so enemies pop up straight away
avi23 6:89d4a7f7588b 528 g_update_screen_flag = true;
avi23 6:89d4a7f7588b 529 g_move_joystick_flag = true;
avi23 6:89d4a7f7588b 530 g_move_enemies_flag = true;
avi23 6:89d4a7f7588b 531 //Forces the missiles to have the fired flags to flase
avi23 6:89d4a7f7588b 532 cannon_missile_on_screen = false;
avi23 6:89d4a7f7588b 533 invader_normal_missile[0].fired = false;
avi23 6:89d4a7f7588b 534 invader_normal_missile[1].fired = false;
avi23 6:89d4a7f7588b 535 }
avi23 6:89d4a7f7588b 536 }
avi23 5:34855f712350 537
avi23 6:89d4a7f7588b 538 if(joystick.get_button_flag()) {
avi23 6:89d4a7f7588b 539 joystick.set_button_flag(0);
avi23 6:89d4a7f7588b 540 }
avi23 6:89d4a7f7588b 541
avi23 6:89d4a7f7588b 542 lcd.refresh();
avi23 6:89d4a7f7588b 543 sleep();
avi23 1:b300d052d549 544 }
avi23 5:34855f712350 545 } else if (game_state == paused) { //Paused screen
avi23 6:89d4a7f7588b 546 //Clears the screen
avi23 6:89d4a7f7588b 547 lcd.clear();
avi23 6:89d4a7f7588b 548 //Resets the fsm state to 0
avi23 6:89d4a7f7588b 549 fsm_state = 0;
avi23 6:89d4a7f7588b 550 PauseScreen();
avi23 5:34855f712350 551 } else if (game_state == game) { //Game screen
avi23 5:34855f712350 552 AttachTickers();
avi23 5:34855f712350 553 Game();
avi23 0:427469992efe 554 }
avi23 2:d34c95990605 555
avi23 0:427469992efe 556 sleep();
avi23 0:427469992efe 557 }
avi23 0:427469992efe 558 }
avi23 0:427469992efe 559
avi23 0:427469992efe 560 void init_K64F()
avi23 0:427469992efe 561 {
avi23 0:427469992efe 562 // on-board LEDs are active-low, so set pin high to turn them off.
avi23 0:427469992efe 563 r_led = 1;
avi23 0:427469992efe 564 g_led = 1;
avi23 0:427469992efe 565 b_led = 1;
avi23 0:427469992efe 566
avi23 0:427469992efe 567 // since the on-board switches have external pull-ups, we should disable the internal pull-down
avi23 0:427469992efe 568 // resistors that are enabled by default using InterruptIn
avi23 0:427469992efe 569 sw2.mode(PullNone);
avi23 0:427469992efe 570 sw3.mode(PullNone);
avi23 0:427469992efe 571 }
avi23 0:427469992efe 572
avi23 0:427469992efe 573 void error()
avi23 0:427469992efe 574 {
avi23 0:427469992efe 575 while(1) { // if error, hang while flashing error message
avi23 0:427469992efe 576 r_led = 0;
avi23 0:427469992efe 577 wait(0.2);
avi23 0:427469992efe 578 r_led = 1;
avi23 0:427469992efe 579 wait(0.2);
avi23 0:427469992efe 580 }
avi23 0:427469992efe 581 }
avi23 0:427469992efe 582
avi23 0:427469992efe 583 void init_serial()
avi23 0:427469992efe 584 {
avi23 0:427469992efe 585 // set to highest baud - ensure terminal software matches
avi23 0:427469992efe 586 pc.baud(115200);
avi23 0:427469992efe 587 }
avi23 0:427469992efe 588
avi23 5:34855f712350 589 //Seeds the random number generator with noise from an analog in pin
avi23 5:34855f712350 590 void init_rng()
avi23 5:34855f712350 591 {
avi23 5:34855f712350 592 AnalogIn rng_seed(PTC10);
avi23 5:34855f712350 593 srand(floor(10000*rng_seed.read()));
avi23 5:34855f712350 594 }
avi23 5:34855f712350 595
avi23 2:d34c95990605 596 void init_shoot()
avi23 0:427469992efe 597 {
avi23 2:d34c95990605 598 shoot_button.mode(PullUp);
avi23 2:d34c95990605 599 shoot_button.fall(&shoot_pressed_isr);
avi23 2:d34c95990605 600 }
avi23 2:d34c95990605 601
avi23 2:d34c95990605 602 void update_screen_isr()
avi23 2:d34c95990605 603 {
avi23 2:d34c95990605 604 g_update_screen_flag = true;
avi23 0:427469992efe 605 }
avi23 0:427469992efe 606
avi23 5:34855f712350 607 void move_enemies_isr()
avi23 5:34855f712350 608 {
avi23 5:34855f712350 609 g_move_enemies_flag = true;
avi23 5:34855f712350 610 }
avi23 5:34855f712350 611
avi23 2:d34c95990605 612 void shoot_pressed_isr()
avi23 2:d34c95990605 613 {
avi23 6:89d4a7f7588b 614 //Only sets the shoot pressed flag 0.1s after the last press
avi23 6:89d4a7f7588b 615 if (!g_shoot_button_debounce_flag) {
avi23 6:89d4a7f7588b 616 g_shoot_pressed_flag = true;
avi23 6:89d4a7f7588b 617 g_shoot_button_debounce_flag = true;
avi23 6:89d4a7f7588b 618
avi23 6:89d4a7f7588b 619 //Attaches a timeout to clear the debounce flag 0.125 seconds after it was set
avi23 6:89d4a7f7588b 620 shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125);
avi23 6:89d4a7f7588b 621 }
avi23 5:34855f712350 622 }
avi23 5:34855f712350 623
avi23 5:34855f712350 624 void move_cannon_missile_isr()
avi23 5:34855f712350 625 {
avi23 5:34855f712350 626 g_move_cannon_missile_flag = true;
avi23 5:34855f712350 627 }
avi23 5:34855f712350 628
avi23 5:34855f712350 629 void move_joystick_isr()
avi23 5:34855f712350 630 {
avi23 5:34855f712350 631 //Always set the move flag in a game
avi23 5:34855f712350 632 if (game_state == game) {
avi23 5:34855f712350 633 g_move_joystick_flag = true;
avi23 5:34855f712350 634 } else if (!g_joystick_cursor_regulator_flag) {
avi23 6:89d4a7f7588b 635 //Only sets the flag if the regulator is not set
avi23 5:34855f712350 636 g_move_joystick_flag = true;
avi23 5:34855f712350 637 g_joystick_cursor_regulator_flag = true;
avi23 5:34855f712350 638
avi23 6:89d4a7f7588b 639 //Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically
avi23 6:89d4a7f7588b 640 joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.1);
avi23 5:34855f712350 641 }
avi23 5:34855f712350 642 }
avi23 5:34855f712350 643
avi23 6:89d4a7f7588b 644 void joystick_cursor_regulator_isr()
avi23 6:89d4a7f7588b 645 {
avi23 5:34855f712350 646 g_joystick_cursor_regulator_flag = false;
avi23 5:34855f712350 647 }
avi23 5:34855f712350 648
avi23 6:89d4a7f7588b 649 void shoot_button_debounce_isr()
avi23 6:89d4a7f7588b 650 {
avi23 6:89d4a7f7588b 651 g_shoot_button_debounce_flag = false;
avi23 6:89d4a7f7588b 652 }
avi23 6:89d4a7f7588b 653
avi23 5:34855f712350 654 void move_invader_normal_missile_0_isr()
avi23 5:34855f712350 655 {
avi23 5:34855f712350 656 g_move_invader_normal_missile_flag[0] = true;
avi23 5:34855f712350 657 }
avi23 5:34855f712350 658
avi23 5:34855f712350 659 void move_invader_normal_missile_1_isr()
avi23 5:34855f712350 660 {
avi23 5:34855f712350 661 g_move_invader_normal_missile_flag[1] = true;
avi23 5:34855f712350 662 }
avi23 5:34855f712350 663
avi23 5:34855f712350 664 void cannon_hit_isr()
avi23 5:34855f712350 665 {
avi23 5:34855f712350 666 g_cannon_hit_flag = false;
avi23 2:d34c95990605 667 }
avi23 2:d34c95990605 668
avi23 5:34855f712350 669 void Game()
avi23 6:89d4a7f7588b 670 {
avi23 5:34855f712350 671 //Stays within the loop while the selected state is game
avi23 5:34855f712350 672 while (game_state == game) {
avi23 5:34855f712350 673 //If the game is over detach all the tickers
avi23 5:34855f712350 674 if (number_of_lives == 0) {
avi23 5:34855f712350 675 DetachTickers();
avi23 5:34855f712350 676
avi23 5:34855f712350 677 lcd.clear();
avi23 5:34855f712350 678 lcd.printString("Game Over.", 1, 2);
avi23 5:34855f712350 679 } else if (no_of_alive_invaders == 0) { //If the player wins a round
avi23 5:34855f712350 680 //Resets the no of alive invaders
avi23 5:34855f712350 681 no_of_alive_invaders = 15;
avi23 5:34855f712350 682 //Detaches the enemy ticker while reinitalising invaders
avi23 5:34855f712350 683 move_enemies.detach();
avi23 5:34855f712350 684 //Reinitalises objects
avi23 5:34855f712350 685 InitSmallInvaders();
avi23 5:34855f712350 686 InitMediumInvaders();
avi23 5:34855f712350 687 InitLargeInvaders();
avi23 5:34855f712350 688 //Reattaches enemy ticker
avi23 5:34855f712350 689 move_enemies.attach(&move_enemies_isr, 1);
avi23 5:34855f712350 690 } else {
avi23 5:34855f712350 691 //Updates pixels on the screen
avi23 5:34855f712350 692 if (g_update_screen_flag) {
avi23 5:34855f712350 693 g_update_screen_flag = false;
avi23 5:34855f712350 694
avi23 5:34855f712350 695 UpdateScreen();
avi23 5:34855f712350 696 }
avi23 5:34855f712350 697
avi23 5:34855f712350 698 //Controls cannon movement
avi23 5:34855f712350 699 if (g_move_joystick_flag) {
avi23 5:34855f712350 700 g_move_joystick_flag = false;
avi23 5:34855f712350 701
avi23 5:34855f712350 702 MoveCannon();
avi23 5:34855f712350 703 DrawBarriers();
avi23 5:34855f712350 704 }
avi23 5:34855f712350 705
avi23 5:34855f712350 706 //Controls enemy movement
avi23 5:34855f712350 707 if (g_move_enemies_flag) {
avi23 5:34855f712350 708 g_move_enemies_flag = false;
avi23 5:34855f712350 709
avi23 5:34855f712350 710 //Increses the speed the invaders move
avi23 5:34855f712350 711 move_enemies.detach();
avi23 5:34855f712350 712 ticker_period = 0.1+(no_of_alive_invaders*0.06);
avi23 5:34855f712350 713 move_enemies.attach(&move_enemies_isr, ticker_period);
avi23 5:34855f712350 714
avi23 5:34855f712350 715 //Clears the old bitmaps
avi23 5:34855f712350 716 ClearSmallInvaders();
avi23 5:34855f712350 717 ClearMediumInvaders();
avi23 5:34855f712350 718 ClearLargeInvaders();
avi23 5:34855f712350 719
avi23 5:34855f712350 720 MoveInvaderXPositions();
avi23 5:34855f712350 721 //Switches the bitmap state
avi23 5:34855f712350 722 invaders_in_state2 = !invaders_in_state2;
avi23 5:34855f712350 723
avi23 5:34855f712350 724 //Draws the invaders
avi23 5:34855f712350 725 DrawSmallInvaders();
avi23 5:34855f712350 726 DrawMediumInvaders();
avi23 5:34855f712350 727 DrawLargeInvaders();
avi23 5:34855f712350 728
avi23 5:34855f712350 729 //Attemots to fire the invaders missiles
avi23 5:34855f712350 730 AttemptToFireInvaderNormalMissiles();
avi23 5:34855f712350 731 }
avi23 5:34855f712350 732
avi23 5:34855f712350 733 //Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
avi23 5:34855f712350 734 if (g_shoot_pressed_flag) {
avi23 5:34855f712350 735 g_shoot_pressed_flag = false;
avi23 5:34855f712350 736
avi23 5:34855f712350 737 if (!cannon_missile_on_screen) {
avi23 5:34855f712350 738 FireCannonMissile();
avi23 5:34855f712350 739 }
avi23 5:34855f712350 740 }
avi23 5:34855f712350 741
avi23 5:34855f712350 742 //Move the cannon shot
avi23 5:34855f712350 743 if (g_move_cannon_missile_flag) {
avi23 5:34855f712350 744 g_move_cannon_missile_flag = false;
avi23 5:34855f712350 745
avi23 5:34855f712350 746 MoveCannonMissile();
avi23 5:34855f712350 747 }
avi23 5:34855f712350 748
avi23 5:34855f712350 749 //Moves the invaders 1st normal missile
avi23 5:34855f712350 750 if (g_move_invader_normal_missile_flag[0]) {
avi23 5:34855f712350 751 g_move_invader_normal_missile_flag[0] = false;
avi23 5:34855f712350 752
avi23 5:34855f712350 753 MoveInvaderNormalMissile(0);
avi23 5:34855f712350 754 }
avi23 5:34855f712350 755
avi23 5:34855f712350 756 //Moves the invaders 2nd normal missile
avi23 5:34855f712350 757 if (g_move_invader_normal_missile_flag[1]) {
avi23 5:34855f712350 758 g_move_invader_normal_missile_flag[1] = false;
avi23 5:34855f712350 759
avi23 5:34855f712350 760 MoveInvaderNormalMissile(1);
avi23 5:34855f712350 761 }
avi23 5:34855f712350 762
avi23 5:34855f712350 763 if (joystick.get_button_flag()) {
avi23 5:34855f712350 764 joystick.set_button_flag(0);
avi23 5:34855f712350 765
avi23 5:34855f712350 766 //Detach all game tickers
avi23 5:34855f712350 767 DetachTickers();
avi23 5:34855f712350 768 game_state = paused;
avi23 5:34855f712350 769 }
avi23 5:34855f712350 770 }
avi23 5:34855f712350 771
avi23 5:34855f712350 772 sleep();
avi23 5:34855f712350 773 }
avi23 2:d34c95990605 774 }
avi23 2:d34c95990605 775
avi23 5:34855f712350 776 void UpdateScreen()
avi23 2:d34c95990605 777 {
avi23 5:34855f712350 778 //Loops through the screen buffer and sets pixels on the LCD
avi23 5:34855f712350 779 for (int col = 0; col < 84; ++col) {
avi23 5:34855f712350 780 for (int row = 0; row < 48; ++row) {
avi23 5:34855f712350 781 if (screen_buffer[col][row]) {
avi23 5:34855f712350 782 lcd.setPixel(col, row);
avi23 5:34855f712350 783 } else {
avi23 5:34855f712350 784 lcd.clearPixel(col, row);
avi23 5:34855f712350 785 }
avi23 5:34855f712350 786 }
avi23 5:34855f712350 787 }
avi23 5:34855f712350 788
avi23 5:34855f712350 789 lcd.refresh();
avi23 2:d34c95990605 790 }
avi23 2:d34c95990605 791
avi23 2:d34c95990605 792 void MoveCannon()
avi23 0:427469992efe 793 {
avi23 0:427469992efe 794 //Clears the ship
avi23 5:34855f712350 795 for (int col = 0; col < 9; ++col) {
avi23 5:34855f712350 796 for (int row = 0; row < 5; ++row) {
avi23 1:b300d052d549 797 if(cannon_bitmap[row][col]) {
avi23 5:34855f712350 798 screen_buffer[cannon_xpos+col][cannon_ypos+row] = empty_pixel;
avi23 0:427469992efe 799 }
avi23 0:427469992efe 800 }
avi23 0:427469992efe 801 }
avi23 0:427469992efe 802
avi23 0:427469992efe 803 //Changes the position of the ship when the joystick is moved, capping at 0 and 75 so it always fits on the screen
avi23 0:427469992efe 804 if (joystick.GetXValue() < 0.25f) {
avi23 1:b300d052d549 805 cannon_xpos--;
avi23 1:b300d052d549 806 if (cannon_xpos < 0) {
avi23 1:b300d052d549 807 cannon_xpos = 0;
avi23 0:427469992efe 808 }
avi23 0:427469992efe 809 } else if (joystick.GetXValue() > 0.75f) {
avi23 1:b300d052d549 810 cannon_xpos++;
avi23 1:b300d052d549 811 if (cannon_xpos > 75) {
avi23 1:b300d052d549 812 cannon_xpos = 75;
avi23 0:427469992efe 813 }
avi23 0:427469992efe 814 }
avi23 0:427469992efe 815
avi23 0:427469992efe 816 //Redraws the ship
avi23 5:34855f712350 817 for (int col = 0; col < 9; ++col) {
avi23 5:34855f712350 818 for (int row = 0; row < 5; ++row) {
avi23 1:b300d052d549 819 if(cannon_bitmap[row][col]) {
avi23 5:34855f712350 820 screen_buffer[cannon_xpos+col][cannon_ypos+row] = cannon_pixel;
avi23 0:427469992efe 821 }
avi23 0:427469992efe 822 }
avi23 0:427469992efe 823 }
avi23 0:427469992efe 824 }
avi23 0:427469992efe 825
avi23 0:427469992efe 826 //Sets the position and aliveness of the small invaders
avi23 0:427469992efe 827 void InitSmallInvaders()
avi23 0:427469992efe 828 {
avi23 5:34855f712350 829 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 830 small_invader[i].x_pos = 2 + (i*13);
avi23 2:d34c95990605 831 small_invader[i].y_pos = 1;
avi23 5:34855f712350 832 small_invader[i].status = alive;
avi23 0:427469992efe 833 }
avi23 0:427469992efe 834 }
avi23 0:427469992efe 835
avi23 5:34855f712350 836 //Cycles through all the small invaders. If they're not already dead clear them
avi23 2:d34c95990605 837 void ClearSmallInvaders()
avi23 2:d34c95990605 838 {
avi23 5:34855f712350 839 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 840 if (small_invader[i].status) {
avi23 5:34855f712350 841 ClearSingleSmallInvader(i);
avi23 5:34855f712350 842 }
avi23 5:34855f712350 843 }
avi23 5:34855f712350 844 }
avi23 5:34855f712350 845
avi23 5:34855f712350 846 //Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
avi23 5:34855f712350 847 void ClearSingleSmallInvader(int invader_no)
avi23 5:34855f712350 848 {
avi23 5:34855f712350 849 for (int col = 0; col < 8; ++col) {
avi23 5:34855f712350 850 for (int row = 0; row < 6; ++row) {
avi23 5:34855f712350 851 if (invaders_in_state2) {
avi23 5:34855f712350 852 if (small_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 853 screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel;
avi23 2:d34c95990605 854 }
avi23 5:34855f712350 855 } else {
avi23 5:34855f712350 856 if (small_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 857 screen_buffer[small_invader[invader_no].x_pos + col][small_invader[invader_no].y_pos + row] = empty_pixel;
avi23 2:d34c95990605 858 }
avi23 2:d34c95990605 859 }
avi23 2:d34c95990605 860 }
avi23 2:d34c95990605 861 }
avi23 5:34855f712350 862
avi23 5:34855f712350 863 small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive;
avi23 2:d34c95990605 864 }
avi23 2:d34c95990605 865
avi23 0:427469992efe 866 void DrawSmallInvaders()
avi23 0:427469992efe 867 {
avi23 5:34855f712350 868 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 869 if (small_invader[i].status == alive) {
avi23 5:34855f712350 870 DrawSingleSmallInvader(i);
avi23 5:34855f712350 871 }
avi23 5:34855f712350 872 }
avi23 5:34855f712350 873 }
avi23 5:34855f712350 874
avi23 5:34855f712350 875 //Cycles through the the screen invader bitmap and sets the pixels in the buffer
avi23 5:34855f712350 876 void DrawSingleSmallInvader(int invader_no)
avi23 5:34855f712350 877 {
avi23 5:34855f712350 878 for (int col = 0; col < 8; ++col) {
avi23 5:34855f712350 879 for (int row = 0; row < 6; ++row) {
avi23 2:d34c95990605 880 if (invaders_in_state2) {
avi23 5:34855f712350 881 if (small_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 882 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 883 }
avi23 0:427469992efe 884 } else {
avi23 5:34855f712350 885 if (small_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 886 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 887 }
avi23 0:427469992efe 888 }
avi23 0:427469992efe 889 }
avi23 0:427469992efe 890 }
avi23 1:b300d052d549 891 }
avi23 1:b300d052d549 892
avi23 1:b300d052d549 893 //Sets the position and aliveness of the medium invaders
avi23 1:b300d052d549 894 void InitMediumInvaders()
avi23 1:b300d052d549 895 {
avi23 5:34855f712350 896 for (int i = 0; i < 5; ++i) {
avi23 1:b300d052d549 897 medium_invader[i].x_pos = 1 + (i*13);
avi23 2:d34c95990605 898 medium_invader[i].y_pos = 8;
avi23 5:34855f712350 899 medium_invader[i].status = alive;
avi23 1:b300d052d549 900 }
avi23 1:b300d052d549 901 }
avi23 1:b300d052d549 902
avi23 2:d34c95990605 903 void ClearMediumInvaders()
avi23 2:d34c95990605 904 {
avi23 5:34855f712350 905 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 906 if (medium_invader[i].status) {
avi23 5:34855f712350 907 ClearSingleMediumInvader(i);
avi23 2:d34c95990605 908 }
avi23 2:d34c95990605 909 }
avi23 2:d34c95990605 910 }
avi23 2:d34c95990605 911
avi23 5:34855f712350 912 void ClearSingleMediumInvader(int invader_no)
avi23 5:34855f712350 913 {
avi23 5:34855f712350 914 for (int col = 0; col < 10; ++col) {
avi23 5:34855f712350 915 for (int row = 0; row < 6; ++row) {
avi23 5:34855f712350 916 if (invaders_in_state2) {
avi23 5:34855f712350 917 if (medium_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 918 screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel;
avi23 5:34855f712350 919 }
avi23 5:34855f712350 920 } else {
avi23 5:34855f712350 921 if (medium_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 922 screen_buffer[medium_invader[invader_no].x_pos + col][medium_invader[invader_no].y_pos + row] = empty_pixel;
avi23 5:34855f712350 923 }
avi23 5:34855f712350 924 }
avi23 5:34855f712350 925 }
avi23 5:34855f712350 926 }
avi23 5:34855f712350 927
avi23 5:34855f712350 928 medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive;
avi23 5:34855f712350 929 }
avi23 5:34855f712350 930
avi23 1:b300d052d549 931 void DrawMediumInvaders()
avi23 1:b300d052d549 932 {
avi23 5:34855f712350 933 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 934 if (medium_invader[i].status == alive) {
avi23 5:34855f712350 935 DrawSingleMediumInvader(i);
avi23 5:34855f712350 936 }
avi23 5:34855f712350 937 }
avi23 5:34855f712350 938 }
avi23 5:34855f712350 939
avi23 5:34855f712350 940 void DrawSingleMediumInvader(int invader_no)
avi23 5:34855f712350 941 {
avi23 5:34855f712350 942 for (int col = 0; col < 10; ++col) {
avi23 5:34855f712350 943 for (int row = 0; row < 6; ++row) {
avi23 2:d34c95990605 944 if (invaders_in_state2) {
avi23 5:34855f712350 945 if (medium_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 946 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 947 }
avi23 1:b300d052d549 948 } else {
avi23 5:34855f712350 949 if (medium_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 950 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 951 }
avi23 1:b300d052d549 952 }
avi23 1:b300d052d549 953 }
avi23 1:b300d052d549 954 }
avi23 1:b300d052d549 955 }
avi23 1:b300d052d549 956
avi23 1:b300d052d549 957 //Sets the position and aliveness of the large invaders
avi23 1:b300d052d549 958 void InitLargeInvaders()
avi23 1:b300d052d549 959 {
avi23 5:34855f712350 960 for (int i = 0; i < 5; ++i) {
avi23 1:b300d052d549 961 large_invader[i].x_pos = 0 + (i*13);
avi23 2:d34c95990605 962 large_invader[i].y_pos = 15;
avi23 5:34855f712350 963 large_invader[i].status = alive;
avi23 5:34855f712350 964 }
avi23 5:34855f712350 965 }
avi23 5:34855f712350 966
avi23 5:34855f712350 967 void ClearLargeInvaders()
avi23 5:34855f712350 968 {
avi23 5:34855f712350 969 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 970 if (large_invader[i].status) {
avi23 5:34855f712350 971 ClearSingleLargeInvader(i);
avi23 5:34855f712350 972 }
avi23 1:b300d052d549 973 }
avi23 1:b300d052d549 974 }
avi23 1:b300d052d549 975
avi23 5:34855f712350 976 //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 977 void ClearSingleLargeInvader(int invader_no)
avi23 2:d34c95990605 978 {
avi23 5:34855f712350 979 for (int col = 0; col < 12; ++col) {
avi23 5:34855f712350 980 for (int row = 0; row < 6; ++row) {
avi23 5:34855f712350 981 if (invaders_in_state2) {
avi23 5:34855f712350 982 if (large_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 983 screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel;
avi23 5:34855f712350 984 }
avi23 5:34855f712350 985 } else {
avi23 5:34855f712350 986 if (large_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 987 screen_buffer[large_invader[invader_no].x_pos + col][large_invader[invader_no].y_pos + row] = empty_pixel;
avi23 2:d34c95990605 988 }
avi23 2:d34c95990605 989 }
avi23 5:34855f712350 990 }
avi23 5:34855f712350 991 }
avi23 5:34855f712350 992
avi23 5:34855f712350 993 large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive;
avi23 5:34855f712350 994 }
avi23 5:34855f712350 995
avi23 5:34855f712350 996 void DrawLargeInvaders()
avi23 5:34855f712350 997 {
avi23 5:34855f712350 998 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 999 if (large_invader[i].status == alive) {
avi23 5:34855f712350 1000 DrawSingleLargeInvader(i);
avi23 5:34855f712350 1001 }
avi23 5:34855f712350 1002 }
avi23 5:34855f712350 1003 }
avi23 5:34855f712350 1004
avi23 5:34855f712350 1005 void DrawSingleLargeInvader(int invader_no)
avi23 5:34855f712350 1006 {
avi23 5:34855f712350 1007 for (int col = 0; col < 12; ++col) {
avi23 5:34855f712350 1008 for (int row = 0; row < 6; ++row) {
avi23 5:34855f712350 1009 if (invaders_in_state2) {
avi23 5:34855f712350 1010 if (large_invader_bitmap_1[row][col]) {
avi23 5:34855f712350 1011 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 1012 }
avi23 5:34855f712350 1013 } else {
avi23 5:34855f712350 1014 if (large_invader_bitmap_2[row][col]) {
avi23 5:34855f712350 1015 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 1016 }
avi23 2:d34c95990605 1017 }
avi23 2:d34c95990605 1018 }
avi23 2:d34c95990605 1019 }
avi23 2:d34c95990605 1020 }
avi23 2:d34c95990605 1021
avi23 2:d34c95990605 1022 void InitBarriers()
avi23 2:d34c95990605 1023 {
avi23 5:34855f712350 1024 for (int i = 0; i < 3; ++i) {
avi23 2:d34c95990605 1025 barrier[i].x_pos = 10 + (i*25);
avi23 2:d34c95990605 1026 barrier[i].y_pos = 33;
avi23 2:d34c95990605 1027 //Copies the bitmap into the structs
avi23 2:d34c95990605 1028 memcpy(barrier[i].before_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
avi23 2:d34c95990605 1029 memcpy(barrier[i].after_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
avi23 2:d34c95990605 1030 }
avi23 2:d34c95990605 1031 }
avi23 2:d34c95990605 1032
avi23 2:d34c95990605 1033 void DrawBarriers()
avi23 2:d34c95990605 1034 {
avi23 2:d34c95990605 1035 //Clears the barrier and redraws it with damage applied
avi23 5:34855f712350 1036 for (int i = 0; i < 3; ++i) {
avi23 5:34855f712350 1037 for (int col = 0; col < 14; ++col) {
avi23 5:34855f712350 1038 for (int row = 0; row < 8; ++row) {
avi23 2:d34c95990605 1039 if (barrier[i].before_bitmap[row][col]) {
avi23 5:34855f712350 1040 screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel;
avi23 2:d34c95990605 1041 }
avi23 2:d34c95990605 1042 if (barrier[i].after_bitmap[row][col]) {
avi23 5:34855f712350 1043 screen_buffer[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i;
avi23 2:d34c95990605 1044 }
avi23 2:d34c95990605 1045 }
avi23 2:d34c95990605 1046 }
avi23 2:d34c95990605 1047 //Copies the after array to the before array
avi23 2:d34c95990605 1048 memcpy(barrier[i].before_bitmap, barrier[i].after_bitmap, sizeof(barrier[i].after_bitmap));
avi23 2:d34c95990605 1049 }
avi23 2:d34c95990605 1050 }
avi23 2:d34c95990605 1051
avi23 5:34855f712350 1052 void MoveInvaderXPositions()
avi23 2:d34c95990605 1053 {
avi23 5:34855f712350 1054 //Checks the left limit
avi23 5:34855f712350 1055 int left_invader_limit = CalculateInvaderLeftLimit();
avi23 5:34855f712350 1056
avi23 5:34855f712350 1057 //Checking the right limit
avi23 5:34855f712350 1058 int right_invader_limit = CalculateInvaderRightLimit();
avi23 5:34855f712350 1059
avi23 5:34855f712350 1060 //End of block
avi23 2:d34c95990605 1061 if (invader_direction == RIGHT) {
avi23 5:34855f712350 1062 MoveInvadersRight(right_invader_limit);
avi23 5:34855f712350 1063 } else {
avi23 2:d34c95990605 1064 //Checks the first large invader to see if it can travel anymore
avi23 5:34855f712350 1065 MoveInvadersLeft(left_invader_limit);
avi23 5:34855f712350 1066 }
avi23 5:34855f712350 1067 }
avi23 5:34855f712350 1068
avi23 5:34855f712350 1069 int CalculateInvaderLeftLimit()
avi23 5:34855f712350 1070 {
avi23 5:34855f712350 1071 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 1072 if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) {
avi23 5:34855f712350 1073 return i;
avi23 5:34855f712350 1074 }
avi23 5:34855f712350 1075 }
avi23 5:34855f712350 1076
avi23 5:34855f712350 1077 //Sort gameover out stuff after
avi23 5:34855f712350 1078 return 4;
avi23 5:34855f712350 1079 }
avi23 5:34855f712350 1080
avi23 5:34855f712350 1081 int CalculateInvaderRightLimit()
avi23 5:34855f712350 1082 {
avi23 5:34855f712350 1083 for (int i = 4; i >= 0; --i) {
avi23 5:34855f712350 1084 if (small_invader[i].status == alive || medium_invader[i].status == alive || large_invader[i].status == alive) {
avi23 5:34855f712350 1085 return i;
avi23 5:34855f712350 1086 }
avi23 5:34855f712350 1087 }
avi23 5:34855f712350 1088
avi23 5:34855f712350 1089 //Sort gameover stuff
avi23 5:34855f712350 1090 return 0;
avi23 5:34855f712350 1091 }
avi23 5:34855f712350 1092
avi23 5:34855f712350 1093 void MoveInvadersLeft(int limit)
avi23 5:34855f712350 1094 {
avi23 5:34855f712350 1095 //Checks the first large invader to see if it can travel anymore
avi23 5:34855f712350 1096 if (large_invader[limit].x_pos > 1) {
avi23 5:34855f712350 1097 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 1098 small_invader[i].x_pos -= 2;
avi23 5:34855f712350 1099 medium_invader[i].x_pos -= 2;
avi23 5:34855f712350 1100 large_invader[i].x_pos -= 2;
avi23 2:d34c95990605 1101 }
avi23 2:d34c95990605 1102 } else {
avi23 5:34855f712350 1103 //Shifts the Invaders down and passes in the new direction
avi23 5:34855f712350 1104 MoveInvaderYPositions(RIGHT);
avi23 2:d34c95990605 1105 }
avi23 2:d34c95990605 1106 }
avi23 2:d34c95990605 1107
avi23 5:34855f712350 1108 void MoveInvadersRight(int limit)
avi23 2:d34c95990605 1109 {
avi23 5:34855f712350 1110 //Checks the first large invader to see if it can travel anymore
avi23 5:34855f712350 1111 if (large_invader[limit].x_pos < 71) {
avi23 5:34855f712350 1112 for (int i = 0; i < 5; ++i) {
avi23 5:34855f712350 1113 small_invader[i].x_pos += 2;
avi23 5:34855f712350 1114 medium_invader[i].x_pos += 2;
avi23 5:34855f712350 1115 large_invader[i].x_pos += 2;
avi23 5:34855f712350 1116 }
avi23 2:d34c95990605 1117 } else {
avi23 5:34855f712350 1118 //Shifts the Invaders down and passes in the new direction
avi23 5:34855f712350 1119 MoveInvaderYPositions(LEFT);
avi23 2:d34c95990605 1120 }
avi23 5:34855f712350 1121 }
avi23 5:34855f712350 1122
avi23 5:34855f712350 1123 void MoveInvaderYPositions(bool new_direction)
avi23 5:34855f712350 1124 {
avi23 5:34855f712350 1125 //Finds the invaders lower limit
avi23 5:34855f712350 1126 Invader lowest_invader = CalculateInvaderYLimit();
avi23 5:34855f712350 1127
avi23 5:34855f712350 1128 //When moving down lowest_invader should not equal none
avi23 5:34855f712350 1129 if (lowest_invader == none) {
avi23 5:34855f712350 1130 error();
avi23 5:34855f712350 1131 }
avi23 5:34855f712350 1132
avi23 2:d34c95990605 1133 //If an invader touches the bottom the game ends, otherwise the invaders descend
avi23 5:34855f712350 1134 if (small_invader[0].y_pos < 33 - (7*lowest_invader)) {
avi23 5:34855f712350 1135 for (int i = 0; i < 5; ++i) {
avi23 2:d34c95990605 1136 small_invader[i].y_pos += 3;
avi23 2:d34c95990605 1137 medium_invader[i].y_pos += 3;
avi23 2:d34c95990605 1138 large_invader[i].y_pos += 3;
avi23 2:d34c95990605 1139 }
avi23 5:34855f712350 1140 invader_direction = new_direction;
avi23 5:34855f712350 1141 } else {
avi23 5:34855f712350 1142 number_of_lives = 0;
avi23 5:34855f712350 1143 }
avi23 5:34855f712350 1144 }
avi23 5:34855f712350 1145
avi23 5:34855f712350 1146 Invader CalculateInvaderYLimit()
avi23 5:34855f712350 1147 {
avi23 5:34855f712350 1148 //Checks to see which row of invaders are still alive to work out maximum y positions
avi23 5:34855f712350 1149 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 1150 return large;
avi23 5:34855f712350 1151 } 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 1152 return medium;
avi23 2:d34c95990605 1153 } else {
avi23 5:34855f712350 1154 return small;
avi23 2:d34c95990605 1155 }
avi23 5:34855f712350 1156 }
avi23 2:d34c95990605 1157
avi23 5:34855f712350 1158 //Queries the invaders on their status and returns the type of invader which is alive
avi23 5:34855f712350 1159 Invader LowestInvaderInColumn(int column)
avi23 5:34855f712350 1160 {
avi23 5:34855f712350 1161 if (large_invader[column].status == alive) {
avi23 5:34855f712350 1162 return large;
avi23 5:34855f712350 1163 } else if (medium_invader[column].status == alive) {
avi23 5:34855f712350 1164 return medium;
avi23 5:34855f712350 1165 } else if (small_invader[column].status == alive) {
avi23 5:34855f712350 1166 return small;
avi23 5:34855f712350 1167 } else {
avi23 5:34855f712350 1168 return none;
avi23 5:34855f712350 1169 }
avi23 2:d34c95990605 1170 }
avi23 2:d34c95990605 1171
avi23 2:d34c95990605 1172 /*
avi23 2:d34c95990605 1173 void InitUFO()
avi23 2:d34c95990605 1174 {
avi23 2:d34c95990605 1175
avi23 2:d34c95990605 1176 }
avi23 2:d34c95990605 1177 */
avi23 2:d34c95990605 1178
avi23 2:d34c95990605 1179 void DrawUFO()
avi23 2:d34c95990605 1180 {
avi23 2:d34c95990605 1181 //Draws the UFO
avi23 2:d34c95990605 1182 int x_pos = 20;
avi23 2:d34c95990605 1183 int y_pos = 25;
avi23 5:34855f712350 1184 for (int col = 0; col < col_no; ++col) {
avi23 5:34855f712350 1185 for (int row = 0; row < row_no; ++row) {
avi23 2:d34c95990605 1186 if(ufo_bitmap[row][col]) {
avi23 5:34855f712350 1187 screen_buffer[x_pos + col][y_pos + row] = ufo_pixel;
avi23 2:d34c95990605 1188 }
avi23 2:d34c95990605 1189 }
avi23 2:d34c95990605 1190 }
avi23 5:34855f712350 1191 }
avi23 5:34855f712350 1192
avi23 5:34855f712350 1193 void FireCannonMissile()
avi23 5:34855f712350 1194 {
avi23 5:34855f712350 1195 cannon_missile_on_screen = true;
avi23 5:34855f712350 1196
avi23 5:34855f712350 1197 //Add 4 to cannon x_pos to get shot x_pos
avi23 5:34855f712350 1198 cannon_missile_x_pos = cannon_xpos + 4;
avi23 5:34855f712350 1199 cannon_missile_y_pos = 40;
avi23 5:34855f712350 1200 move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
avi23 5:34855f712350 1201 }
avi23 5:34855f712350 1202
avi23 5:34855f712350 1203 void MoveCannonMissile()
avi23 5:34855f712350 1204 {
avi23 5:34855f712350 1205 //Checks bullet will not go beyond the bounds of the screen buffer
avi23 5:34855f712350 1206 if (cannon_missile_y_pos > -1) {
avi23 5:34855f712350 1207 //Loops throught the shot bitmap and clears the pixels in the screen buffer
avi23 5:34855f712350 1208 for (int row = 0; row < 4; ++row) {
avi23 5:34855f712350 1209 //Clears the position where the bullet was
avi23 5:34855f712350 1210 screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
avi23 5:34855f712350 1211 }
avi23 5:34855f712350 1212
avi23 5:34855f712350 1213 //Increments the shot going up the screen
avi23 5:34855f712350 1214 --cannon_missile_y_pos;
avi23 5:34855f712350 1215
avi23 5:34855f712350 1216 //Checks to see if the shot will hit anything
avi23 5:34855f712350 1217 CollisionDetectionCannonMissile();
avi23 5:34855f712350 1218 } else {
avi23 5:34855f712350 1219 //Loops throught the shot bitmap and clears the pixels in the screen buffer
avi23 5:34855f712350 1220 for (int row = 1; row < 4; ++row) {
avi23 5:34855f712350 1221 //Clears the position where the bullet was
avi23 5:34855f712350 1222 screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
avi23 5:34855f712350 1223 }
avi23 5:34855f712350 1224
avi23 5:34855f712350 1225 cannon_missile_on_screen = false;
avi23 5:34855f712350 1226 move_cannon_missile.detach();
avi23 5:34855f712350 1227 }
avi23 5:34855f712350 1228 }
avi23 5:34855f712350 1229
avi23 5:34855f712350 1230 void MoveInvaderNormalMissile(int missile_no)
avi23 5:34855f712350 1231 {
avi23 5:34855f712350 1232 //Checks missile will not exceed screen buffer
avi23 5:34855f712350 1233 if (invader_normal_missile[missile_no].y_pos < 44) {
avi23 5:34855f712350 1234 //Loops through the bitmap and clears the missile from the screen buffer
avi23 5:34855f712350 1235 for (int col = 0; col < 3; ++col) {
avi23 5:34855f712350 1236 for (int row = 0; row < 4; ++row) {
avi23 5:34855f712350 1237 if (invader_normal_missile_bitmap[row][col]) {
avi23 5:34855f712350 1238 screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel;
avi23 5:34855f712350 1239 }
avi23 5:34855f712350 1240 }
avi23 5:34855f712350 1241 }
avi23 5:34855f712350 1242
avi23 5:34855f712350 1243 //Increments the position of the missile
avi23 5:34855f712350 1244 ++invader_normal_missile[missile_no].y_pos;
avi23 5:34855f712350 1245
avi23 5:34855f712350 1246 //Collision detection
avi23 5:34855f712350 1247 CollisionDetectionInvaderNormalMissile(missile_no);
avi23 5:34855f712350 1248
avi23 5:34855f712350 1249 } else {
avi23 5:34855f712350 1250 //Loops through the bitmap and clears the pixels still on the screen
avi23 5:34855f712350 1251 for (int col = 0; col < 3; ++col) {
avi23 5:34855f712350 1252 for (int row = 0; row < 4; ++row) {
avi23 5:34855f712350 1253 if (invader_normal_missile_bitmap[row][col]) {
avi23 5:34855f712350 1254 screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = empty_pixel;
avi23 5:34855f712350 1255 }
avi23 5:34855f712350 1256 }
avi23 5:34855f712350 1257 }
avi23 5:34855f712350 1258
avi23 5:34855f712350 1259 invader_normal_missile[missile_no].fired = false;
avi23 5:34855f712350 1260 move_invader_normal_missile[missile_no].detach();
avi23 5:34855f712350 1261 }
avi23 5:34855f712350 1262 }
avi23 5:34855f712350 1263
avi23 5:34855f712350 1264 //Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer
avi23 5:34855f712350 1265 void CollisionDetectionCannonMissile()
avi23 5:34855f712350 1266 {
avi23 5:34855f712350 1267 for (int row = 0; row < 4; ++row) {
avi23 5:34855f712350 1268 int object_no;
avi23 5:34855f712350 1269 if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_small_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_small_invader_pixel + 5)) { //Collides with a small invader
avi23 5:34855f712350 1270 object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader);
avi23 5:34855f712350 1271 ClearSingleSmallInvader(object_no);
avi23 5:34855f712350 1272 score += 40;
avi23 5:34855f712350 1273 break;
avi23 5:34855f712350 1274 } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_medium_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_medium_invader_pixel + 5)) { //Collides with a medium invader
avi23 5:34855f712350 1275 object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader);
avi23 5:34855f712350 1276 ClearSingleMediumInvader(object_no);
avi23 5:34855f712350 1277 score += 20;
avi23 5:34855f712350 1278 break;
avi23 5:34855f712350 1279 } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_large_invader_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_large_invader_pixel + 5)) { //Collides with a large invader
avi23 5:34855f712350 1280 object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader);
avi23 5:34855f712350 1281 ClearSingleLargeInvader(object_no);
avi23 5:34855f712350 1282 score += 10;
avi23 5:34855f712350 1283 break;
avi23 5:34855f712350 1284 } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] >= first_barrier_pixel && screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] < (first_barrier_pixel + 3)) { //Collides with a barrier
avi23 5:34855f712350 1285 CannonMissileHitBarrier(first_barrier_pixel, row);
avi23 5:34855f712350 1286 DrawBarriers();
avi23 5:34855f712350 1287 break;
avi23 5:34855f712350 1288 } else if (screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] == ufo_pixel) { //Collides with a UFO
avi23 5:34855f712350 1289 pc.printf("UFO Hit\n");
avi23 5:34855f712350 1290 cannon_missile_on_screen = false;
avi23 5:34855f712350 1291 move_cannon_missile.detach();
avi23 5:34855f712350 1292 break;
avi23 5:34855f712350 1293 } else {
avi23 5:34855f712350 1294 screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = cannon_missile_pixel;
avi23 5:34855f712350 1295 }
avi23 5:34855f712350 1296 }
avi23 5:34855f712350 1297 }
avi23 5:34855f712350 1298
avi23 5:34855f712350 1299 //Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer
avi23 5:34855f712350 1300 void CollisionDetectionInvaderNormalMissile(int missile_no)
avi23 5:34855f712350 1301 {
avi23 5:34855f712350 1302 //Invader missile coordinates shifted to match centre bottom of bitmap
avi23 5:34855f712350 1303 int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1;
avi23 5:34855f712350 1304 int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3;
avi23 5:34855f712350 1305 if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) {
avi23 5:34855f712350 1306 //Decrements the number of lives, pauses the game for 2 seconds
avi23 5:34855f712350 1307 //Marks the cannon as hit
avi23 5:34855f712350 1308 g_cannon_hit_flag = true;
avi23 5:34855f712350 1309 //Detaches all tickers
avi23 5:34855f712350 1310 DetachTickers();
avi23 6:89d4a7f7588b 1311 //Creates a Timeout object on the stack with a period of 2 seconds to pause the game for 2 seconds
avi23 6:89d4a7f7588b 1312 Timeout cannon_hit;
avi23 5:34855f712350 1313 cannon_hit.attach(&cannon_hit_isr, 2);
avi23 5:34855f712350 1314 while (g_cannon_hit_flag) {
avi23 5:34855f712350 1315 sleep();
avi23 5:34855f712350 1316 }
avi23 5:34855f712350 1317 AttachTickers();
avi23 5:34855f712350 1318 --number_of_lives;
avi23 5:34855f712350 1319 invader_normal_missile[missile_no].fired = false;
avi23 5:34855f712350 1320 move_invader_normal_missile[missile_no].detach();
avi23 5:34855f712350 1321 } 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 5:34855f712350 1322 //Finds barrier number
avi23 5:34855f712350 1323 InvaderNormalMissileHitBarrier(first_barrier_pixel, invader_normal_missile[missile_no]);
avi23 5:34855f712350 1324 invader_normal_missile[missile_no].fired = false;
avi23 5:34855f712350 1325 move_invader_normal_missile[missile_no].detach();
avi23 5:34855f712350 1326 } else {
avi23 5:34855f712350 1327 for (int col = 0; col < 3; ++col) {
avi23 5:34855f712350 1328 for (int row = 0; row < 4; ++row) {
avi23 5:34855f712350 1329 if (invader_normal_missile_bitmap[row][col]) {
avi23 5:34855f712350 1330 screen_buffer[invader_normal_missile[missile_no].x_pos + col][invader_normal_missile[missile_no].y_pos + row] = invader_normal_missile_pixel;
avi23 5:34855f712350 1331 }
avi23 5:34855f712350 1332 }
avi23 5:34855f712350 1333 }
avi23 5:34855f712350 1334 }
avi23 5:34855f712350 1335 }
avi23 5:34855f712350 1336
avi23 5:34855f712350 1337 //Finds the invader number the shot hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen
avi23 5:34855f712350 1338 int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5])
avi23 5:34855f712350 1339 {
avi23 5:34855f712350 1340 int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel;
avi23 5:34855f712350 1341 invader[invader_no].status = dying;
avi23 5:34855f712350 1342 cannon_missile_on_screen = false;
avi23 5:34855f712350 1343 --no_of_alive_invaders;
avi23 5:34855f712350 1344 move_cannon_missile.detach();
avi23 5:34855f712350 1345
avi23 5:34855f712350 1346 return invader_no;
avi23 5:34855f712350 1347 }
avi23 5:34855f712350 1348
avi23 5:34855f712350 1349 //Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
avi23 5:34855f712350 1350 void CannonMissileHitBarrier(int first_pixel, int row)
avi23 5:34855f712350 1351 {
avi23 5:34855f712350 1352 int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel;
avi23 5:34855f712350 1353 //Essentially inverse of barrier init
avi23 5:34855f712350 1354 int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1;
avi23 5:34855f712350 1355 int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; //Don't know why it's -1 and not -2
avi23 5:34855f712350 1356 //Loops through the damage bitmap and modifies the barrier's after bitmap
avi23 5:34855f712350 1357 for (int col = 0; col < 3; ++col) {
avi23 5:34855f712350 1358 for (int row_bit = 0; row_bit < 3; ++row_bit) {
avi23 5:34855f712350 1359 //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
avi23 5:34855f712350 1360 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 1361 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 1362 }
avi23 5:34855f712350 1363 }
avi23 5:34855f712350 1364 }
avi23 5:34855f712350 1365 cannon_missile_on_screen = false;
avi23 5:34855f712350 1366 move_cannon_missile.detach();
avi23 5:34855f712350 1367 }
avi23 5:34855f712350 1368
avi23 5:34855f712350 1369 //Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
avi23 5:34855f712350 1370 void InvaderNormalMissileHitBarrier(int first_pixel, const struct InvaderNormalMissiles (&missile))
avi23 5:34855f712350 1371 {
avi23 5:34855f712350 1372 int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_pixel;
avi23 5:34855f712350 1373 //Essentially inverse of barrier init
avi23 5:34855f712350 1374 int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1;
avi23 5:34855f712350 1375 int relative_y_pos = (missile.y_pos + 3) - 33;
avi23 5:34855f712350 1376 //Loops through the damage bitmap and modifies the barrier's after bitmap
avi23 5:34855f712350 1377 for (int col = 0; col < 3; ++col) {
avi23 5:34855f712350 1378 for (int row_bit = 0; row_bit < 2; ++row_bit) {
avi23 5:34855f712350 1379 //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
avi23 5:34855f712350 1380 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 1381 barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col];
avi23 5:34855f712350 1382 }
avi23 5:34855f712350 1383 }
avi23 5:34855f712350 1384 }
avi23 5:34855f712350 1385 }
avi23 5:34855f712350 1386
avi23 5:34855f712350 1387 void AttemptToFireInvaderNormalMissiles()
avi23 5:34855f712350 1388 {
avi23 5:34855f712350 1389 //Fires the normal missiles
avi23 5:34855f712350 1390 //Loops through the 2 allowed missiles and if they're not on the screen, randomly fire
avi23 5:34855f712350 1391 for (int i = 0; i < 2; ++i) {
avi23 5:34855f712350 1392 if (!invader_normal_missile[i].fired) {
avi23 5:34855f712350 1393 //If the random mumber is 1, fire a missile
avi23 5:34855f712350 1394 //Higher chance when there are less invaders on the screen, up to a 1/3 chance
avi23 5:34855f712350 1395 if ((rand() % (no_of_alive_invaders + 2)) == 1) {
avi23 5:34855f712350 1396 // if ((rand() % 5) == 1) {
avi23 5:34855f712350 1397 int fired_column;
avi23 5:34855f712350 1398 int loop_limit = 0; //Stops loop from never ending
avi23 5:34855f712350 1399 Invader missile_source;
avi23 5:34855f712350 1400 do {
avi23 5:34855f712350 1401 fired_column = rand() % 5;
avi23 5:34855f712350 1402 missile_source = LowestInvaderInColumn(fired_column);
avi23 5:34855f712350 1403 ++loop_limit;
avi23 5:34855f712350 1404 } while (missile_source == none && loop_limit < 10);
avi23 5:34855f712350 1405
avi23 5:34855f712350 1406 //Finds the centre point of the chosen invader and fires the missile
avi23 5:34855f712350 1407 //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 1408 if (missile_source == none) {
avi23 5:34855f712350 1409 continue;
avi23 5:34855f712350 1410 } else if (missile_source == large) {
avi23 5:34855f712350 1411 FireNormalInvaderMissile(i, missile_source, large_invader[fired_column]);
avi23 5:34855f712350 1412 } else if (missile_source == medium) {
avi23 5:34855f712350 1413 FireNormalInvaderMissile(i, missile_source, medium_invader[fired_column]);
avi23 5:34855f712350 1414 } else {
avi23 5:34855f712350 1415 FireNormalInvaderMissile(i, missile_source, small_invader[fired_column]);
avi23 5:34855f712350 1416 }
avi23 5:34855f712350 1417 }
avi23 5:34855f712350 1418 }
avi23 5:34855f712350 1419 }
avi23 5:34855f712350 1420 }
avi23 5:34855f712350 1421
avi23 5:34855f712350 1422 //Pass by reference to re
avi23 5:34855f712350 1423 void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader))
avi23 5:34855f712350 1424 {
avi23 5:34855f712350 1425 //Finds the centre point of the chosen invader and fires the missile
avi23 5:34855f712350 1426 //Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3
avi23 5:34855f712350 1427 invader_normal_missile[missile_no].x_pos = invader.x_pos + (3 + source);
avi23 5:34855f712350 1428 invader_normal_missile[missile_no].y_pos = invader.y_pos + 6;
avi23 5:34855f712350 1429 invader_normal_missile[missile_no].fired = true;
avi23 5:34855f712350 1430
avi23 5:34855f712350 1431 //Uses a function pointer to attach the ticker
avi23 5:34855f712350 1432 move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05);
avi23 5:34855f712350 1433 }
avi23 5:34855f712350 1434
avi23 5:34855f712350 1435 void DetachTickers()
avi23 5:34855f712350 1436 {
avi23 5:34855f712350 1437 update_screen.detach();
avi23 5:34855f712350 1438 move_enemies.detach();
avi23 5:34855f712350 1439 if (cannon_missile_on_screen) {
avi23 5:34855f712350 1440 move_cannon_missile.detach();
avi23 5:34855f712350 1441 }
avi23 5:34855f712350 1442 for (int i = 0; i < 2; ++i) {
avi23 5:34855f712350 1443 if (invader_normal_missile[i].fired) {
avi23 5:34855f712350 1444 move_invader_normal_missile[i].detach();
avi23 5:34855f712350 1445 }
avi23 5:34855f712350 1446 }
avi23 5:34855f712350 1447 }
avi23 5:34855f712350 1448
avi23 5:34855f712350 1449 void AttachTickers()
avi23 5:34855f712350 1450 {
avi23 5:34855f712350 1451 update_screen.attach(&update_screen_isr, 0.05);
avi23 5:34855f712350 1452 move_enemies.attach(&move_enemies_isr, ticker_period);
avi23 5:34855f712350 1453
avi23 5:34855f712350 1454 if (cannon_missile_on_screen) {
avi23 5:34855f712350 1455 move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
avi23 5:34855f712350 1456 }
avi23 5:34855f712350 1457 for (int i = 0; i < 2; ++i) {
avi23 5:34855f712350 1458 if (invader_normal_missile[i].fired) {
avi23 5:34855f712350 1459 move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05);
avi23 5:34855f712350 1460 }
avi23 5:34855f712350 1461 }
avi23 6:89d4a7f7588b 1462 }
avi23 6:89d4a7f7588b 1463
avi23 6:89d4a7f7588b 1464 void PauseScreen()
avi23 6:89d4a7f7588b 1465 {
avi23 6:89d4a7f7588b 1466 while (game_state == paused) {
avi23 6:89d4a7f7588b 1467 //Prints the pause screen, score etc
avi23 6:89d4a7f7588b 1468 PrintPauseScreen();
avi23 6:89d4a7f7588b 1469
avi23 6:89d4a7f7588b 1470 //Draws the cursor
avi23 6:89d4a7f7588b 1471 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 6:89d4a7f7588b 1472 lcd.drawRect(74, cursor_y_pos, 2, 2, 1); //Draws the cursor
avi23 6:89d4a7f7588b 1473
avi23 6:89d4a7f7588b 1474 if (g_move_joystick_flag) {
avi23 6:89d4a7f7588b 1475 g_move_joystick_flag = false;
avi23 6:89d4a7f7588b 1476
avi23 6:89d4a7f7588b 1477 //Moves the cursor to match the selected option, only if the joystick isn't centred
avi23 6:89d4a7f7588b 1478 MoveCursor(fsm_paused);
avi23 6:89d4a7f7588b 1479 }
avi23 6:89d4a7f7588b 1480
avi23 6:89d4a7f7588b 1481 //If the button is pressed the selected option will appear on the screen
avi23 6:89d4a7f7588b 1482 if (g_shoot_pressed_flag) {
avi23 6:89d4a7f7588b 1483 g_shoot_pressed_flag = false;
avi23 6:89d4a7f7588b 1484 game_state = fsm_paused[fsm_state].output;
avi23 6:89d4a7f7588b 1485 }
avi23 6:89d4a7f7588b 1486
avi23 6:89d4a7f7588b 1487 //Resets the joystick flag to false if pressed
avi23 6:89d4a7f7588b 1488 if (joystick.get_button_flag()) {
avi23 6:89d4a7f7588b 1489 joystick.set_button_flag(0);
avi23 6:89d4a7f7588b 1490 }
avi23 6:89d4a7f7588b 1491
avi23 6:89d4a7f7588b 1492 lcd.refresh();
avi23 6:89d4a7f7588b 1493
avi23 6:89d4a7f7588b 1494 sleep();
avi23 6:89d4a7f7588b 1495 }
avi23 6:89d4a7f7588b 1496 }
avi23 6:89d4a7f7588b 1497
avi23 6:89d4a7f7588b 1498 void PrintPauseScreen()
avi23 6:89d4a7f7588b 1499 {
avi23 6:89d4a7f7588b 1500 //Prints paused and a line underneath
avi23 6:89d4a7f7588b 1501 lcd.printString("Paused", 24, 0);
avi23 6:89d4a7f7588b 1502 //Displays the current score
avi23 6:89d4a7f7588b 1503 char buffer[14];
avi23 6:89d4a7f7588b 1504 sprintf(buffer, "Score: %d", score);
avi23 6:89d4a7f7588b 1505 lcd.printString(buffer, 0, 1);
avi23 6:89d4a7f7588b 1506 //Displays the no of lives
avi23 6:89d4a7f7588b 1507 sprintf(buffer, "Lives: %d", number_of_lives);
avi23 6:89d4a7f7588b 1508 lcd.printString(buffer, 0, 2);
avi23 6:89d4a7f7588b 1509 lcd.drawLine(0, 23, 83, 23, 2);
avi23 6:89d4a7f7588b 1510 //Prints options on pause menu
avi23 6:89d4a7f7588b 1511 lcd.printString("Resume", 5, 3);
avi23 6:89d4a7f7588b 1512 lcd.printString("Save", 5, 4);
avi23 6:89d4a7f7588b 1513 lcd.printString("Quit", 5, 5);
avi23 6:89d4a7f7588b 1514 }
avi23 6:89d4a7f7588b 1515
avi23 6:89d4a7f7588b 1516 void MoveCursor(const struct FSMMenus *fsm)
avi23 6:89d4a7f7588b 1517 {
avi23 6:89d4a7f7588b 1518 //If the joystick is is pushed down half way clear the cursor and set the next state
avi23 6:89d4a7f7588b 1519 if (joystick.GetYValue() < 0.25f) {
avi23 6:89d4a7f7588b 1520 //Clears the cursor
avi23 6:89d4a7f7588b 1521 lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
avi23 6:89d4a7f7588b 1522 //Sets the new state
avi23 6:89d4a7f7588b 1523 fsm_state = fsm[fsm_state].next_state[0];
avi23 6:89d4a7f7588b 1524 } else if (joystick.GetYValue() > 0.75f) {
avi23 6:89d4a7f7588b 1525 //Clears the cursor
avi23 6:89d4a7f7588b 1526 lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
avi23 6:89d4a7f7588b 1527 //Sets the new state
avi23 6:89d4a7f7588b 1528 fsm_state = fsm[fsm_state].next_state[1];
avi23 6:89d4a7f7588b 1529 }
avi23 0:427469992efe 1530 }