Final Submission. I have read and agreed with Statement of Academic Integrity.

Dependencies:   mbed

Committer:
Nicholas75179
Date:
Fri May 22 10:28:29 2020 +0000
Revision:
2:bb50c3a9a05c
Parent:
1:3727d33a171b
published 11:27 22/5/2020

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Nicholas75179 1:3727d33a171b 1 /*
Nicholas75179 1:3727d33a171b 2 ELEC2645 Embedded Systems Project
Nicholas75179 1:3727d33a171b 3 School of Electronic & Electrical Engineering
Nicholas75179 1:3727d33a171b 4 University of Leeds
Nicholas75179 1:3727d33a171b 5 Name: Nicholas Wu
Nicholas75179 1:3727d33a171b 6 Username: el18nw
Nicholas75179 1:3727d33a171b 7 Student ID Number: 201275179
Nicholas75179 1:3727d33a171b 8 Date: 22/5/2020
Nicholas75179 1:3727d33a171b 9 */
Nicholas75179 0:fde420d18f42 10
Nicholas75179 0:fde420d18f42 11 #include "mbed.h"
Nicholas75179 0:fde420d18f42 12 #include "Gamepad.h"
Nicholas75179 0:fde420d18f42 13 #include "N5110.h"
Nicholas75179 0:fde420d18f42 14 #include "Bitmap.h"
Nicholas75179 0:fde420d18f42 15 #include "Spaceship.h"
Nicholas75179 0:fde420d18f42 16
Nicholas75179 0:fde420d18f42 17 // IN-GAME DEBUGGING FLAGS
Nicholas75179 0:fde420d18f42 18 bool DEBUG_menu = 0;
Nicholas75179 0:fde420d18f42 19 bool sound_on = 1;
Nicholas75179 0:fde420d18f42 20 // During development a mixture of serial port and in-game debugging methods
Nicholas75179 0:fde420d18f42 21 // I found in-game debugging to be more interesting and accessible
Nicholas75179 0:fde420d18f42 22 // Thus I had left these two debugging options here as examples
Nicholas75179 0:fde420d18f42 23
Nicholas75179 0:fde420d18f42 24 // OBJECTS
Nicholas75179 0:fde420d18f42 25 Gamepad pad;
Nicholas75179 0:fde420d18f42 26 N5110 lcd;
Nicholas75179 0:fde420d18f42 27 Bitmap AGALAG(title, 10, 48); // name, y and x width
Nicholas75179 0:fde420d18f42 28 Bitmap SHIP0(player_ship0, 9, 12);
Nicholas75179 0:fde420d18f42 29 Bitmap SHIP1(player_ship1, 9, 12);
Nicholas75179 0:fde420d18f42 30 Spaceship player;
Nicholas75179 0:fde420d18f42 31 Spaceship enemy[2];
Nicholas75179 0:fde420d18f42 32 // Declaring enemies as an array makes adding more enemies simple
Nicholas75179 0:fde420d18f42 33 // for this platform 2 allows for a playable framerate
Nicholas75179 0:fde420d18f42 34
Nicholas75179 0:fde420d18f42 35 // FUNCTIONS & RESPECTIVE VARIABLES
Nicholas75179 0:fde420d18f42 36 void dramatic_print(string, int, int, int);
Nicholas75179 0:fde420d18f42 37 int temptime = clock();
Nicholas75179 0:fde420d18f42 38 char g_buffer[14] = "0";
Nicholas75179 0:fde420d18f42 39 void title_sequence();
Nicholas75179 0:fde420d18f42 40 float g_x = 0, g_y = 0;
Nicholas75179 0:fde420d18f42 41 void create_stars();
Nicholas75179 0:fde420d18f42 42 bool g_star_map[224][224];
Nicholas75179 0:fde420d18f42 43 bool check_stars(int, int);
Nicholas75179 0:fde420d18f42 44 void print_background(float, float, float);
Nicholas75179 0:fde420d18f42 45 void menu();
Nicholas75179 0:fde420d18f42 46 void help();
Nicholas75179 0:fde420d18f42 47 void ship_select();
Nicholas75179 0:fde420d18f42 48 int player_ship_type = 0;
Nicholas75179 0:fde420d18f42 49 bool difficulty = 0;
Nicholas75179 0:fde420d18f42 50 bool god_mode = 0;
Nicholas75179 0:fde420d18f42 51 void print_menu(int, int);
Nicholas75179 0:fde420d18f42 52 void level_system();
Nicholas75179 0:fde420d18f42 53 int points = 0;
Nicholas75179 0:fde420d18f42 54 void engine_setup(bool);
Nicholas75179 0:fde420d18f42 55 void engine(bool, float);
Nicholas75179 0:fde420d18f42 56 void render_objects(int);
Nicholas75179 0:fde420d18f42 57 void draw_enemy(int, int, int);
Nicholas75179 0:fde420d18f42 58 void effects(bool, int, float);
Nicholas75179 0:fde420d18f42 59 void sound(bool);
Nicholas75179 0:fde420d18f42 60 bool explode(int, int);
Nicholas75179 0:fde420d18f42 61 void print_tracker(int i);
Nicholas75179 0:fde420d18f42 62
Nicholas75179 0:fde420d18f42 63 int main() {
Nicholas75179 0:fde420d18f42 64 lcd.init();
Nicholas75179 0:fde420d18f42 65 lcd.inverseMode();
Nicholas75179 0:fde420d18f42 66 lcd.setContrast(0.48);
Nicholas75179 0:fde420d18f42 67 pad.init();
Nicholas75179 0:fde420d18f42 68 lcd.backLightOn();
Nicholas75179 0:fde420d18f42 69 create_stars();
Nicholas75179 0:fde420d18f42 70 title_sequence();
Nicholas75179 0:fde420d18f42 71 while (1) menu();
Nicholas75179 0:fde420d18f42 72 }
Nicholas75179 0:fde420d18f42 73
Nicholas75179 0:fde420d18f42 74 void menu() {
Nicholas75179 0:fde420d18f42 75 int menu = 0, selection = 0;
Nicholas75179 0:fde420d18f42 76
Nicholas75179 0:fde420d18f42 77 while (1) {
Nicholas75179 0:fde420d18f42 78 lcd.clear();
Nicholas75179 0:fde420d18f42 79 print_background(1, 0, 0);
Nicholas75179 0:fde420d18f42 80 print_menu(menu, selection);
Nicholas75179 0:fde420d18f42 81 AGALAG.render(lcd, 18, 5);
Nicholas75179 0:fde420d18f42 82
Nicholas75179 0:fde420d18f42 83 if (pad.B_held()) selection++;
Nicholas75179 0:fde420d18f42 84 if (pad.X_held()) selection--;
Nicholas75179 0:fde420d18f42 85 while (pad.B_held() || pad.X_held());
Nicholas75179 0:fde420d18f42 86 if (selection < 0) selection = 3;
Nicholas75179 0:fde420d18f42 87 else if (selection > 3) selection = 0;
Nicholas75179 0:fde420d18f42 88 if (DEBUG_menu) {
Nicholas75179 0:fde420d18f42 89 sprintf(g_buffer, " %1i,%1i", menu, selection);
Nicholas75179 0:fde420d18f42 90 lcd.printString(g_buffer, 0, 5);
Nicholas75179 0:fde420d18f42 91 }
Nicholas75179 0:fde420d18f42 92 lcd.refresh();
Nicholas75179 0:fde420d18f42 93
Nicholas75179 0:fde420d18f42 94 if (pad.A_held() || pad.Y_held()) {
Nicholas75179 0:fde420d18f42 95 if (menu == 3) {
Nicholas75179 0:fde420d18f42 96 if (selection == 0) sound_on = !sound_on;
Nicholas75179 0:fde420d18f42 97 if (selection == 1) points += 100;;
Nicholas75179 0:fde420d18f42 98 if (selection == 2) DEBUG_menu = !DEBUG_menu;
Nicholas75179 0:fde420d18f42 99 if (selection == 3) menu = 0;
Nicholas75179 0:fde420d18f42 100 }else if (menu==1) {
Nicholas75179 0:fde420d18f42 101 if (selection == 0) ship_select();
Nicholas75179 0:fde420d18f42 102 if (selection == 1) god_mode =! god_mode;
Nicholas75179 0:fde420d18f42 103 if (selection == 2) difficulty =! difficulty;
Nicholas75179 0:fde420d18f42 104 if (selection == 3) menu = 0;
Nicholas75179 0:fde420d18f42 105 }else if (menu == 0) {
Nicholas75179 0:fde420d18f42 106 if (selection == 0) level_system();
Nicholas75179 0:fde420d18f42 107 if (selection == 1) menu = 1;
Nicholas75179 0:fde420d18f42 108 if (selection == 2) help();
Nicholas75179 0:fde420d18f42 109 if (selection == 3) menu = 3;
Nicholas75179 0:fde420d18f42 110 }
Nicholas75179 0:fde420d18f42 111 //this while statement captures the frame so no more than
Nicholas75179 0:fde420d18f42 112 //one increment could happen with each button press
Nicholas75179 0:fde420d18f42 113 while (pad.A_held() || pad.Y_held());
Nicholas75179 0:fde420d18f42 114 }
Nicholas75179 0:fde420d18f42 115 }
Nicholas75179 0:fde420d18f42 116 }
Nicholas75179 0:fde420d18f42 117
Nicholas75179 0:fde420d18f42 118 void print_menu(int menu, int selection) {
Nicholas75179 0:fde420d18f42 119 //selected menu item is denoted as such: >example<
Nicholas75179 0:fde420d18f42 120 if (menu == 0) {
Nicholas75179 0:fde420d18f42 121 if (selection == 0) lcd.printString(">PLAY!<", 21, 2);
Nicholas75179 0:fde420d18f42 122 else lcd.printString("PLAY!", 27, 2);
Nicholas75179 0:fde420d18f42 123 if (selection == 1) lcd.printString(">OPTIONS<", 15, 3);
Nicholas75179 0:fde420d18f42 124 else lcd.printString("OPTIONS", 21, 3);
Nicholas75179 0:fde420d18f42 125 if (selection == 2) lcd.printString(">CONTROLS<", 12, 4);
Nicholas75179 0:fde420d18f42 126 else lcd.printString("CONTROLS", 18, 4);
Nicholas75179 0:fde420d18f42 127 if (selection == 3) lcd.printString(">DEBUG<", 21, 5);
Nicholas75179 0:fde420d18f42 128 else lcd.printString("DEBUG", 27, 5);
Nicholas75179 0:fde420d18f42 129 }
Nicholas75179 0:fde420d18f42 130 if (menu == 1) {
Nicholas75179 0:fde420d18f42 131 if (selection == 0) lcd.printString(">SHIP=0<", 18, 2);
Nicholas75179 0:fde420d18f42 132 else lcd.printString("SHIP=0", 24, 2);
Nicholas75179 0:fde420d18f42 133 lcd.printChar(player_ship_type+49, 54, 2);
Nicholas75179 0:fde420d18f42 134 if (selection == 1) lcd.printString(">GOD MODE=0<", 6, 3);
Nicholas75179 0:fde420d18f42 135 else lcd.printString("GOD MODE=0", 12, 3);
Nicholas75179 0:fde420d18f42 136 lcd.printChar(48+god_mode, 66, 3);
Nicholas75179 0:fde420d18f42 137 if (selection == 2) lcd.printString(">EASY MODE<", 9, 4);
Nicholas75179 0:fde420d18f42 138 else lcd.printString("EASY MODE", 15, 4);
Nicholas75179 0:fde420d18f42 139 if (difficulty) lcd.printString("HARD", 15, 4);
Nicholas75179 0:fde420d18f42 140 if (selection == 3) lcd.printString(">BACK<", 24, 5);
Nicholas75179 0:fde420d18f42 141 else lcd.printString("BACK", 30, 5);
Nicholas75179 0:fde420d18f42 142 }
Nicholas75179 0:fde420d18f42 143 if (menu==3) {
Nicholas75179 0:fde420d18f42 144 if (selection == 0) lcd.printString(">SOUND=0<", 15, 2);
Nicholas75179 0:fde420d18f42 145 else lcd.printString("SOUND=0", 21, 2);
Nicholas75179 0:fde420d18f42 146 if (sound_on) lcd.printString("1", 57, 2);
Nicholas75179 0:fde420d18f42 147 if (selection == 1) lcd.printString(">POINTS= 0<", 3, 3);
Nicholas75179 0:fde420d18f42 148 else lcd.printString("POINTS= 0", 9, 3);
Nicholas75179 0:fde420d18f42 149 sprintf(g_buffer, "%4i", points);
Nicholas75179 0:fde420d18f42 150 lcd.printString(g_buffer, 52, 3);
Nicholas75179 0:fde420d18f42 151 if (selection == 2) lcd.printString(">MENU DB=0<", 9, 4);
Nicholas75179 0:fde420d18f42 152 else lcd.printString("MENU DB=0", 15, 4);
Nicholas75179 0:fde420d18f42 153 if (DEBUG_menu) lcd.printString("1", 63, 4);
Nicholas75179 0:fde420d18f42 154 if (selection == 3) lcd.printString(">BACK<", 24, 5);
Nicholas75179 0:fde420d18f42 155 else lcd.printString("BACK", 30, 5);
Nicholas75179 0:fde420d18f42 156 }
Nicholas75179 0:fde420d18f42 157 }
Nicholas75179 0:fde420d18f42 158
Nicholas75179 0:fde420d18f42 159 void ship_select() {
Nicholas75179 0:fde420d18f42 160 player_ship_type++;
Nicholas75179 0:fde420d18f42 161 player_ship_type %= 2;
Nicholas75179 0:fde420d18f42 162 //selects between one of two
Nicholas75179 0:fde420d18f42 163 //ship types available
Nicholas75179 0:fde420d18f42 164 }
Nicholas75179 0:fde420d18f42 165
Nicholas75179 0:fde420d18f42 166 void level_system() {
Nicholas75179 0:fde420d18f42 167 while (!pad.start_held()) {
Nicholas75179 0:fde420d18f42 168 create_stars();
Nicholas75179 0:fde420d18f42 169 engine_setup(int(points/400));
Nicholas75179 0:fde420d18f42 170 //passing the result of this division saves calculation during gameplay
Nicholas75179 0:fde420d18f42 171 if (enemy[0].HP <= 0 && enemy[1].HP <= 0 && player.HP <= 0) {
Nicholas75179 0:fde420d18f42 172 lcd.printString("<ACCEPTABLE>", 6, 4);
Nicholas75179 0:fde420d18f42 173 }
Nicholas75179 0:fde420d18f42 174 else if (player.HP <= 0) lcd.printString("<GAME OVER>", 9, 4);
Nicholas75179 0:fde420d18f42 175 else if (enemy[0].HP <= 0 && enemy[1].HP <= 0) {
Nicholas75179 0:fde420d18f42 176 lcd.printString("<NICE>", 24, 4);
Nicholas75179 0:fde420d18f42 177 points += 100;
Nicholas75179 0:fde420d18f42 178 if (difficulty) points += 100;
Nicholas75179 0:fde420d18f42 179 if (points>400) points += 100;
Nicholas75179 0:fde420d18f42 180 } else lcd.printString("<TOO SLOW>", 12, 4);
Nicholas75179 0:fde420d18f42 181 //above checks victory conditions, extra points for difficulty
Nicholas75179 0:fde420d18f42 182 sprintf(g_buffer, "SCORE:%4i", points);
Nicholas75179 0:fde420d18f42 183 if (enemy[0].HP > 0 || enemy[1].HP > 0) points = 0;
Nicholas75179 0:fde420d18f42 184 lcd.printString(g_buffer, 12, 5);
Nicholas75179 0:fde420d18f42 185 lcd.refresh();
Nicholas75179 0:fde420d18f42 186 wait_ms(200);
Nicholas75179 0:fde420d18f42 187 if (points <= 200) lcd.printString("<EXIT: START>", 6, 0);
Nicholas75179 0:fde420d18f42 188 lcd.printString("<PLAY: ABXY>", 9, 1);
Nicholas75179 0:fde420d18f42 189 lcd.refresh();
Nicholas75179 0:fde420d18f42 190 while (!pad.A_held() && !pad.B_held() && !pad.Y_held()
Nicholas75179 0:fde420d18f42 191 && !pad.X_held() && !pad.start_held());
Nicholas75179 0:fde420d18f42 192 }
Nicholas75179 0:fde420d18f42 193 pad.leds(0);
Nicholas75179 0:fde420d18f42 194 }
Nicholas75179 0:fde420d18f42 195
Nicholas75179 0:fde420d18f42 196 void engine_setup (bool phase_two) {
Nicholas75179 0:fde420d18f42 197 float HP_divider;
Nicholas75179 0:fde420d18f42 198 //init_ship sets parameters - position, direction,
Nicholas75179 0:fde420d18f42 199 //turn rate, acceleration, speed and hitpoints
Nicholas75179 0:fde420d18f42 200 if (player_ship_type == 0) {
Nicholas75179 0:fde420d18f42 201 player.init_ship(1, 0, 0, 0.05, 0.05, 0.7, 12);
Nicholas75179 0:fde420d18f42 202 HP_divider = 0.5; //HP divider is used to display health on the LEDs
Nicholas75179 0:fde420d18f42 203 } else {
Nicholas75179 0:fde420d18f42 204 player.init_ship(1, 0, 0, 0.15, 0.15, 0.5, 20);
Nicholas75179 0:fde420d18f42 205 HP_divider = 0.3;
Nicholas75179 0:fde420d18f42 206 } //ship type 2: slower speed and fire rate,
Nicholas75179 0:fde420d18f42 207 //faster turn rate, higher damage and more HP
Nicholas75179 0:fde420d18f42 208 enemy[0].init_ship(40, -20+rand()%40, -1+rand()%2,
Nicholas75179 0:fde420d18f42 209 0.06+0.00005*points, 0.08+0.0001*points, 0.7+0.001*points, 10);
Nicholas75179 0:fde420d18f42 210 //additional maths in the enemy initialisation
Nicholas75179 0:fde420d18f42 211 //to increase difficulty over time
Nicholas75179 0:fde420d18f42 212 if (difficulty) for (int i = 0; i <= 1; i++) {
Nicholas75179 0:fde420d18f42 213 enemy[i].init_ship(50+rand()%30, 10-20*i, 2-4*i,
Nicholas75179 0:fde420d18f42 214 0.06+0.00005*points, 0.1+0.0001*points, 1+0.001*points, 10);
Nicholas75179 0:fde420d18f42 215 } else if (phase_two) for (int i = 0; i <= 1; i++) {
Nicholas75179 0:fde420d18f42 216 enemy[i].init_ship(50+rand()%30, 10-20*i, -1+2*i,
Nicholas75179 0:fde420d18f42 217 0.05+0.00005*points, 0.05+0.0001*points, 0.4+0.001*points, 10);
Nicholas75179 0:fde420d18f42 218 }
Nicholas75179 0:fde420d18f42 219 engine(phase_two, HP_divider);
Nicholas75179 0:fde420d18f42 220 }
Nicholas75179 0:fde420d18f42 221
Nicholas75179 0:fde420d18f42 222 void engine(bool phase_two, float HP_divider) {
Nicholas75179 0:fde420d18f42 223 int end_delay = 40, time_limit = clock() + 6000;
Nicholas75179 0:fde420d18f42 224 // end_delay lets the animation continue for about two seconds after death
Nicholas75179 0:fde420d18f42 225 // time_limit keeps the game fun by forcing players to engage with the game
Nicholas75179 0:fde420d18f42 226
Nicholas75179 0:fde420d18f42 227 while (end_delay > 0 && clock() < time_limit) {
Nicholas75179 0:fde420d18f42 228 Vector2D coord=pad.get_mapped_coord();
Nicholas75179 0:fde420d18f42 229 lcd.clear();
Nicholas75179 0:fde420d18f42 230
Nicholas75179 0:fde420d18f42 231 for (int i = 0; i <= (difficulty || phase_two); i++) {
Nicholas75179 0:fde420d18f42 232 if (enemy[i].HP > 0) {
Nicholas75179 0:fde420d18f42 233 enemy[i].AI_controls(player.pos_x, player.pos_y, player.orientation);
Nicholas75179 0:fde420d18f42 234 }
Nicholas75179 0:fde420d18f42 235 if (enemy[i].check_hitbox(int(player.pos_x), int(player.pos_y), 4)) {
Nicholas75179 0:fde420d18f42 236 player.HP--;
Nicholas75179 0:fde420d18f42 237 }
Nicholas75179 0:fde420d18f42 238 if (player.check_hitbox(int(enemy[i].pos_x), int(enemy[i].pos_y), 5)) {
Nicholas75179 0:fde420d18f42 239 if (player_ship_type == 0)enemy[i].HP--;
Nicholas75179 0:fde420d18f42 240 else enemy[i].HP -= 4; //cannon on ship1 does more damage
Nicholas75179 0:fde420d18f42 241 }
Nicholas75179 0:fde420d18f42 242 enemy[i].update();
Nicholas75179 0:fde420d18f42 243 }//change the for loop and object declaration to add more enemies
Nicholas75179 0:fde420d18f42 244
Nicholas75179 0:fde420d18f42 245 if (player_ship_type == 0) SHIP0.render(lcd, 60, 20);
Nicholas75179 0:fde420d18f42 246 else SHIP1.render(lcd, 60, 20);
Nicholas75179 0:fde420d18f42 247
Nicholas75179 0:fde420d18f42 248 render_objects(phase_two || difficulty);
Nicholas75179 0:fde420d18f42 249 effects(phase_two, time_limit, HP_divider);
Nicholas75179 0:fde420d18f42 250 // effects control every other aspect of the gamepad output
Nicholas75179 0:fde420d18f42 251
Nicholas75179 0:fde420d18f42 252 if (player.HP > 0) {
Nicholas75179 0:fde420d18f42 253 player.controls(player_ship_type, pad.Y_held(),
Nicholas75179 0:fde420d18f42 254 pad.A_held(), pad.X_held(), pad.B_held(), coord.x, coord.y);
Nicholas75179 0:fde420d18f42 255 }
Nicholas75179 0:fde420d18f42 256 if ((enemy[0].HP<=0 && enemy[1].HP <= 0) || player.HP <= 0) end_delay--;
Nicholas75179 0:fde420d18f42 257 if (god_mode) player.HP = 24;
Nicholas75179 0:fde420d18f42 258
Nicholas75179 0:fde420d18f42 259 lcd.refresh();
Nicholas75179 0:fde420d18f42 260 // I opted not to limit the frame rate of the game because
Nicholas75179 0:fde420d18f42 261 // it will never render fast enough to be less fun
Nicholas75179 0:fde420d18f42 262 // as if it was running at full speed
Nicholas75179 0:fde420d18f42 263 }
Nicholas75179 0:fde420d18f42 264 }
Nicholas75179 0:fde420d18f42 265
Nicholas75179 0:fde420d18f42 266 void render_objects(int extra_enemies) {
Nicholas75179 0:fde420d18f42 267 int temp1, temp2;
Nicholas75179 0:fde420d18f42 268 float sine = sin(player.orientation), cosine = cos(player.orientation);
Nicholas75179 0:fde420d18f42 269
Nicholas75179 0:fde420d18f42 270 for (int i = -16; i < 69; i++) {
Nicholas75179 0:fde420d18f42 271 for (int ii = -24; ii < 32; ii++) {
Nicholas75179 0:fde420d18f42 272 temp1 = int(player.pos_x + (i * cosine - ii * sine));
Nicholas75179 0:fde420d18f42 273 temp2 = int(player.pos_y + (ii * cosine + i * sine));
Nicholas75179 0:fde420d18f42 274
Nicholas75179 0:fde420d18f42 275 if (temp1 == int(enemy[0].pos_x)
Nicholas75179 0:fde420d18f42 276 && temp2 == int(enemy[0].pos_y)) {
Nicholas75179 0:fde420d18f42 277 draw_enemy(i, ii, 0);
Nicholas75179 0:fde420d18f42 278 #ifdef DEBUG_render
Nicholas75179 0:fde420d18f42 279 printf("Found enemy0: %3.1f,%3.1f\n",
Nicholas75179 0:fde420d18f42 280 enemy[0].pos_x, enemy[0].pos_y);
Nicholas75179 0:fde420d18f42 281 #endif
Nicholas75179 0:fde420d18f42 282
Nicholas75179 0:fde420d18f42 283 } else if (extra_enemies && temp1 == int(enemy[1].pos_x)
Nicholas75179 0:fde420d18f42 284 && temp2 == int(enemy[1].pos_y)) {
Nicholas75179 0:fde420d18f42 285 draw_enemy(i, ii, 1);
Nicholas75179 0:fde420d18f42 286 #ifdef DEBUG_render
Nicholas75179 0:fde420d18f42 287 printf("Found enemy1: %3.1f,%3.1f\n",
Nicholas75179 0:fde420d18f42 288 enemy[1].pos_x, enemy[1].pos_y);
Nicholas75179 0:fde420d18f42 289 #endif
Nicholas75179 0:fde420d18f42 290 }
Nicholas75179 0:fde420d18f42 291 else if (check_stars(temp1, temp2)
Nicholas75179 0:fde420d18f42 292 || player.check_bullets(temp1, temp2)
Nicholas75179 0:fde420d18f42 293 || enemy[0].check_bullets(temp1, temp2)
Nicholas75179 0:fde420d18f42 294 || enemy[1].check_bullets(temp1, temp2)){
Nicholas75179 0:fde420d18f42 295 lcd.setPixel(68-i, 24-ii, 1);
Nicholas75179 0:fde420d18f42 296 }
Nicholas75179 0:fde420d18f42 297 }// above finds the location of particles to render
Nicholas75179 0:fde420d18f42 298 }
Nicholas75179 0:fde420d18f42 299 }
Nicholas75179 0:fde420d18f42 300
Nicholas75179 0:fde420d18f42 301 void draw_enemy(int i, int j, int num) {
Nicholas75179 0:fde420d18f42 302 float angle = player.orientation - enemy[num].orientation - 1.5708f;
Nicholas75179 0:fde420d18f42 303 //this calculation finds what direction
Nicholas75179 0:fde420d18f42 304 //to draw the enemy with respect to the player
Nicholas75179 0:fde420d18f42 305
Nicholas75179 0:fde420d18f42 306 if (enemy[num].HP > 0) {
Nicholas75179 0:fde420d18f42 307 lcd.drawRect(63 - i, 32 - j, 12, 4, FILL_TRANSPARENT); //health bar
Nicholas75179 0:fde420d18f42 308 lcd.drawRect(64 - i, 33 - j, enemy[num].HP, 2, FILL_BLACK);
Nicholas75179 0:fde420d18f42 309
Nicholas75179 0:fde420d18f42 310 if (j < 20) {//limits the game to drawing within bound of the screen
Nicholas75179 0:fde420d18f42 311 lcd.drawCircle(68 - i, 24 - j, 5, FILL_BLACK);
Nicholas75179 0:fde420d18f42 312 lcd.drawCircle(68 - i + 3 * sin(angle),
Nicholas75179 0:fde420d18f42 313 24 - j + 3 * cos(angle), 2, FILL_WHITE);
Nicholas75179 0:fde420d18f42 314 }
Nicholas75179 0:fde420d18f42 315 } else if (explode (68 - i, 24 - j) && j < 20) {
Nicholas75179 0:fde420d18f42 316 lcd.drawCircle(68 - i, 24 - j, 5, FILL_BLACK);
Nicholas75179 0:fde420d18f42 317 lcd.drawCircle(68 - i + 3 * sin(angle),
Nicholas75179 0:fde420d18f42 318 24 - j + 3 * cos(angle), 2, FILL_WHITE);
Nicholas75179 0:fde420d18f42 319 }
Nicholas75179 0:fde420d18f42 320 }
Nicholas75179 0:fde420d18f42 321
Nicholas75179 0:fde420d18f42 322 void effects(bool phase_two, int time_limit, float HP_divider) {
Nicholas75179 0:fde420d18f42 323 if (enemy[0].HP > 0) print_tracker(0);
Nicholas75179 0:fde420d18f42 324 if ((difficulty || phase_two) && (enemy[1].HP > 0)) print_tracker(1);
Nicholas75179 0:fde420d18f42 325 if (pad.X_held() && clock() % 18 > 8) {
Nicholas75179 0:fde420d18f42 326 for (int i = 0; i < 3; i++)lcd.setPixel(69 + i, 24 , 1);
Nicholas75179 0:fde420d18f42 327 if (clock() % 9 > 3) {
Nicholas75179 0:fde420d18f42 328 lcd.setPixel(72, 24, 1);
Nicholas75179 0:fde420d18f42 329 lcd.setPixel(73, 24, 1);
Nicholas75179 0:fde420d18f42 330 }
Nicholas75179 0:fde420d18f42 331 }
Nicholas75179 0:fde420d18f42 332 pad.leds(0); //LEDs display player health proportionally
Nicholas75179 0:fde420d18f42 333 if (player.HP > 0) {
Nicholas75179 0:fde420d18f42 334 for (int health = 0; health <= (HP_divider*player.HP); health++) {
Nicholas75179 0:fde420d18f42 335 pad.led(health, 1);
Nicholas75179 0:fde420d18f42 336 }
Nicholas75179 0:fde420d18f42 337 }
Nicholas75179 0:fde420d18f42 338 else explode(68, 24);
Nicholas75179 0:fde420d18f42 339 if (sound_on) sound(difficulty || phase_two);
Nicholas75179 0:fde420d18f42 340 sprintf(g_buffer, "%2i", (time_limit - clock()) / 100);
Nicholas75179 0:fde420d18f42 341 lcd.printString(g_buffer, 12, 5);
Nicholas75179 0:fde420d18f42 342 }
Nicholas75179 0:fde420d18f42 343
Nicholas75179 0:fde420d18f42 344 void print_tracker(int num) {
Nicholas75179 0:fde420d18f42 345 float diff_x = enemy[num].pos_x-player.pos_x;
Nicholas75179 0:fde420d18f42 346 if (abs(diff_x) < 0.0001f) diff_x = 0.0001f;
Nicholas75179 0:fde420d18f42 347
Nicholas75179 0:fde420d18f42 348 float angle_to_enemy = atan((enemy[num].pos_y - player.pos_y) / diff_x);
Nicholas75179 0:fde420d18f42 349 if ((diff_x) > 0) angle_to_enemy += 3.1416f;
Nicholas75179 0:fde420d18f42 350
Nicholas75179 0:fde420d18f42 351 #ifdef DEBUG_tracker
Nicholas75179 0:fde420d18f42 352 sprintf(g_buffer, "%1.3f", player.orientation);
Nicholas75179 0:fde420d18f42 353 lcd.printString(g_buffer, 60, 0);
Nicholas75179 0:fde420d18f42 354 sprintf(g_buffer, "%1.3f", angle_to_enemy - player.orientation);
Nicholas75179 0:fde420d18f42 355 lcd.printString(g_buffer, 60, 1);
Nicholas75179 0:fde420d18f42 356 #endif
Nicholas75179 0:fde420d18f42 357
Nicholas75179 0:fde420d18f42 358 float sine = sin(angle_to_enemy - player.orientation);
Nicholas75179 0:fde420d18f42 359 float cosine = cos(angle_to_enemy - player.orientation);
Nicholas75179 0:fde420d18f42 360
Nicholas75179 0:fde420d18f42 361 lcd.setPixel(67 + 8 * cosine, 24 + 6 * sine, 1);
Nicholas75179 0:fde420d18f42 362 lcd.setPixel(67 + 9 * cosine, 24 + 7 * sine, 1);
Nicholas75179 0:fde420d18f42 363 lcd.setPixel(67 + 10 * cosine, 24 + 8 * sine, 1);
Nicholas75179 0:fde420d18f42 364 lcd.setPixel(67 + 11 * cosine, 24 + 9 * sine, 1);
Nicholas75179 0:fde420d18f42 365 lcd.setPixel(67 + 12 * cosine, 24 + 10 * sine, 1);
Nicholas75179 0:fde420d18f42 366 lcd.setPixel(67 + 13 * cosine, 24 + 11 * sine, 1);
Nicholas75179 0:fde420d18f42 367 lcd.drawCircle(67 + 9 * cosine, 24 + 7 * sine, 1, FILL_BLACK);
Nicholas75179 0:fde420d18f42 368 lcd.drawCircle(67 + 10 * cosine, 24 + 8 * sine, 1, FILL_BLACK);
Nicholas75179 0:fde420d18f42 369 }
Nicholas75179 0:fde420d18f42 370
Nicholas75179 0:fde420d18f42 371 void sound(bool extra_enemy) {
Nicholas75179 0:fde420d18f42 372 //buzzers can only produce one tone at a time
Nicholas75179 0:fde420d18f42 373 //this function prioritises some sounds over others
Nicholas75179 0:fde420d18f42 374 if (player.HP <= 0) {
Nicholas75179 0:fde420d18f42 375 player.explosion_FX--;
Nicholas75179 0:fde420d18f42 376 }
Nicholas75179 0:fde420d18f42 377 if (enemy[0].HP <= 0) {
Nicholas75179 0:fde420d18f42 378 enemy[0].explosion_FX--;
Nicholas75179 0:fde420d18f42 379 }
Nicholas75179 0:fde420d18f42 380 if (extra_enemy && enemy[1].HP <= 0) {
Nicholas75179 0:fde420d18f42 381 enemy[1].explosion_FX--;
Nicholas75179 0:fde420d18f42 382 }
Nicholas75179 0:fde420d18f42 383 //"explosion" is initialised as 8, and is decremented each frame
Nicholas75179 0:fde420d18f42 384 //below if statement makes the explosion produce noise over 7 frames
Nicholas75179 0:fde420d18f42 385 if ((player.explosion_FX < 8 && player.explosion_FX > 0)
Nicholas75179 0:fde420d18f42 386 || (enemy[0].explosion_FX < 8 && enemy[0].explosion_FX > 0)
Nicholas75179 0:fde420d18f42 387 || (extra_enemy && enemy[1].explosion_FX < 8 && enemy[1].explosion_FX > 0)) {
Nicholas75179 0:fde420d18f42 388 pad.tone(1000, 0.1);
Nicholas75179 0:fde420d18f42 389 }
Nicholas75179 0:fde420d18f42 390 else if (player.gun_FX > 0) pad.tone(1600 - player.gun_FX * 200, 0.1);
Nicholas75179 0:fde420d18f42 391 //the player's weapon takes priority for sound, after explosions
Nicholas75179 0:fde420d18f42 392 else if (enemy[0].gun_FX > 0) pad.tone(5000, 0.1);
Nicholas75179 0:fde420d18f42 393 else if (enemy[1].gun_FX > 0) pad.tone(5000, 0.1);
Nicholas75179 0:fde420d18f42 394
Nicholas75179 0:fde420d18f42 395 enemy[0].gun_FX--;
Nicholas75179 0:fde420d18f42 396 enemy[1].gun_FX--;
Nicholas75179 0:fde420d18f42 397 player.gun_FX--;
Nicholas75179 0:fde420d18f42 398 //decrementing the FX variable makes sure the sound is not delayed
Nicholas75179 0:fde420d18f42 399 //if the function is busy producing a different sound
Nicholas75179 0:fde420d18f42 400 }
Nicholas75179 0:fde420d18f42 401
Nicholas75179 0:fde420d18f42 402 bool explode(int i, int j) {
Nicholas75179 0:fde420d18f42 403 //a clock() with a modulo helps make the explosion more exciting
Nicholas75179 0:fde420d18f42 404 //by forcing it to switch on and off over time
Nicholas75179 0:fde420d18f42 405 if (clock() % 9 > 4) {
Nicholas75179 0:fde420d18f42 406 for (int inc = 0; inc < 6; inc++) {
Nicholas75179 0:fde420d18f42 407 float b = rand() % 63 / 10;
Nicholas75179 0:fde420d18f42 408 int a = rand() % 6;
Nicholas75179 0:fde420d18f42 409 int tempx = i - a * sin(b), tempy = j - a * cos(b);
Nicholas75179 0:fde420d18f42 410
Nicholas75179 0:fde420d18f42 411 if (tempy > 3 && i < 81) lcd.drawCircle(tempx, tempy, 2, FILL_BLACK);
Nicholas75179 0:fde420d18f42 412 }//6 randomly placed white packets to simulate explosion
Nicholas75179 0:fde420d18f42 413 return 0;
Nicholas75179 0:fde420d18f42 414 }//boolean returns are used for switching a rendering function in draw_enemy();
Nicholas75179 0:fde420d18f42 415 return 1;
Nicholas75179 0:fde420d18f42 416 }
Nicholas75179 0:fde420d18f42 417
Nicholas75179 0:fde420d18f42 418 void print_background(float screen_x, float screen_y, float screen_orientation) {
Nicholas75179 0:fde420d18f42 419 int temp1, temp2;
Nicholas75179 0:fde420d18f42 420 float sine = sin(screen_orientation), cosine = cos(screen_orientation);
Nicholas75179 0:fde420d18f42 421
Nicholas75179 0:fde420d18f42 422 for (int i = -16; i < 69; i++ ) {
Nicholas75179 0:fde420d18f42 423 for (int ii = -24; ii < 25; ii++) {
Nicholas75179 0:fde420d18f42 424 temp1 = int(screen_x + (i * cosine - ii * sine));
Nicholas75179 0:fde420d18f42 425 temp2 = int(screen_y + (ii * cosine + i * sine)) + 1;
Nicholas75179 0:fde420d18f42 426
Nicholas75179 0:fde420d18f42 427 if (check_stars(temp1, temp2)) lcd.setPixel(68 - i, 24 - ii, 1);
Nicholas75179 0:fde420d18f42 428 }
Nicholas75179 0:fde420d18f42 429 }
Nicholas75179 0:fde420d18f42 430 }
Nicholas75179 0:fde420d18f42 431
Nicholas75179 0:fde420d18f42 432 bool check_stars(int temp1, int temp2) {
Nicholas75179 0:fde420d18f42 433 while (temp1 < 0) temp1 += 224;
Nicholas75179 0:fde420d18f42 434 temp1 = temp1 % 224; //this function tesselates the star map
Nicholas75179 0:fde420d18f42 435 while (temp2 < 0) temp2 += 224;
Nicholas75179 0:fde420d18f42 436 temp2 = temp2 % 224;
Nicholas75179 0:fde420d18f42 437
Nicholas75179 0:fde420d18f42 438 if (g_star_map[temp1][temp2])return 1;
Nicholas75179 0:fde420d18f42 439 else return 0;
Nicholas75179 0:fde420d18f42 440 }
Nicholas75179 0:fde420d18f42 441
Nicholas75179 0:fde420d18f42 442 void create_stars() {//the backhround is a boolean array
Nicholas75179 0:fde420d18f42 443 for (int i = 0; i < 224; i++) {
Nicholas75179 0:fde420d18f42 444 for (int ii = 0; ii < 224; ii++) g_star_map[i][ii] = 0;
Nicholas75179 0:fde420d18f42 445 }//this clears the background for drawing a new one
Nicholas75179 0:fde420d18f42 446 for (int i = 0; i < 224; i++) {
Nicholas75179 0:fde420d18f42 447 for (int ii = 0; ii < 224; ii++) {
Nicholas75179 0:fde420d18f42 448 if (rand() % 1000 > 985) g_star_map[i][ii] = 1;
Nicholas75179 0:fde420d18f42 449 }//1.5% of the sky is stars!
Nicholas75179 0:fde420d18f42 450 }
Nicholas75179 0:fde420d18f42 451 }
Nicholas75179 0:fde420d18f42 452
Nicholas75179 0:fde420d18f42 453 void title_sequence() {
Nicholas75179 0:fde420d18f42 454 temptime = clock();
Nicholas75179 0:fde420d18f42 455
Nicholas75179 0:fde420d18f42 456 while ((clock() - temptime) < 40) {
Nicholas75179 0:fde420d18f42 457 lcd.clear();
Nicholas75179 0:fde420d18f42 458 print_background(1, 0, 0);
Nicholas75179 0:fde420d18f42 459 lcd.refresh();
Nicholas75179 0:fde420d18f42 460 }
Nicholas75179 0:fde420d18f42 461 sprintf(g_buffer, "Space Combat");
Nicholas75179 0:fde420d18f42 462
Nicholas75179 0:fde420d18f42 463 while (!pad.A_held() && !pad.B_held() && !pad.Y_held()
Nicholas75179 0:fde420d18f42 464 && !pad.X_held() && !pad.start_held()) {
Nicholas75179 0:fde420d18f42 465 AGALAG.render(lcd, 18, 12);
Nicholas75179 0:fde420d18f42 466 if ((clock() - temptime) < 240) dramatic_print(g_buffer, 7, 3, 20);
Nicholas75179 0:fde420d18f42 467 lcd.refresh();
Nicholas75179 0:fde420d18f42 468 }
Nicholas75179 0:fde420d18f42 469 temptime = clock();
Nicholas75179 0:fde420d18f42 470
Nicholas75179 0:fde420d18f42 471 while (clock() - temptime < 140 && !pad.start_held()) {
Nicholas75179 0:fde420d18f42 472 lcd.clear();
Nicholas75179 0:fde420d18f42 473 print_background(1, 0, 0);
Nicholas75179 0:fde420d18f42 474 AGALAG.render(lcd, 18, 11 - (clock() - temptime) / 20);
Nicholas75179 0:fde420d18f42 475 lcd.refresh();
Nicholas75179 0:fde420d18f42 476 }
Nicholas75179 0:fde420d18f42 477 }
Nicholas75179 0:fde420d18f42 478
Nicholas75179 0:fde420d18f42 479 void dramatic_print(string str, int offset, int line_num, int delay_time) {
Nicholas75179 0:fde420d18f42 480 int i = ((clock() - temptime) / delay_time) % 14;
Nicholas75179 0:fde420d18f42 481
Nicholas75179 0:fde420d18f42 482 for (int ii = 0; ii <= i; ii++) {
Nicholas75179 0:fde420d18f42 483 lcd.printChar(str[ii], 6 * ii + offset, line_num);
Nicholas75179 0:fde420d18f42 484 }
Nicholas75179 0:fde420d18f42 485 }
Nicholas75179 0:fde420d18f42 486
Nicholas75179 0:fde420d18f42 487 void help() {
Nicholas75179 0:fde420d18f42 488 while (pad.A_held() || pad.Y_held());
Nicholas75179 0:fde420d18f42 489 pad.leds(1.0);
Nicholas75179 0:fde420d18f42 490
Nicholas75179 0:fde420d18f42 491 while (!pad.A_held() && !pad.B_held() && !pad.Y_held()
Nicholas75179 0:fde420d18f42 492 && !pad.X_held() && !pad.start_held()) {
Nicholas75179 0:fde420d18f42 493 Vector2D coord = pad.get_mapped_coord();
Nicholas75179 0:fde420d18f42 494 lcd.clear();
Nicholas75179 0:fde420d18f42 495 print_background(1, 0, 0);
Nicholas75179 0:fde420d18f42 496 lcd.printString("<HP=LED>", 19, 0);
Nicholas75179 0:fde420d18f42 497 lcd.printString("<SHOOT>", 0, 1);
Nicholas75179 0:fde420d18f42 498 lcd.printString("<MOVE>", 45, 1);
Nicholas75179 0:fde420d18f42 499 lcd.printString(">BACK<", 24, 5);
Nicholas75179 0:fde420d18f42 500 lcd.drawCircle(63, 36, 3, FILL_TRANSPARENT);
Nicholas75179 0:fde420d18f42 501 lcd.drawCircle(63, 20, 3, FILL_TRANSPARENT);
Nicholas75179 0:fde420d18f42 502 lcd.drawCircle(53, 28, 3, FILL_TRANSPARENT);
Nicholas75179 0:fde420d18f42 503 lcd.drawCircle(73, 28, 3, FILL_TRANSPARENT);
Nicholas75179 0:fde420d18f42 504 lcd.drawCircle(20 + int(10 * coord.x),
Nicholas75179 0:fde420d18f42 505 28 - int(10 * coord.y), 3, FILL_BLACK);
Nicholas75179 0:fde420d18f42 506
Nicholas75179 0:fde420d18f42 507 if (clock() % 4 > 1) lcd.drawCircle(20, 28, 12, FILL_TRANSPARENT);
Nicholas75179 0:fde420d18f42 508 lcd.refresh();
Nicholas75179 0:fde420d18f42 509 }
Nicholas75179 0:fde420d18f42 510 pad.leds(0);
Nicholas75179 0:fde420d18f42 511 }