Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407
Dependencies: Joystick N5110 SDFileSystem mbed
main.cpp@5:34855f712350, 2016-04-27 (annotated)
- 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?
User | Revision | Line number | New 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 | } |