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

Dependencies:   Joystick N5110 SDFileSystem mbed

Committer:
avi23
Date:
Wed Apr 27 00:19:52 2016 +0000
Revision:
5:34855f712350
Parent:
4:a99953ef9e42
Child:
6:89d4a7f7588b
Most things done. (commit is before altering invader bitmaps)

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