James Heavey
/
EL17JH
FINAL VERSION
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 ///////// pre-processor directives //////// 00002 00003 #include "mbed.h" 00004 #include "Gamepad.h" 00005 #include "N5110.h" 00006 #include "BreakoutEngine.h" 00007 #include "Bitmap.h" 00008 #include "Sprites.h" 00009 #include "SDFileSystem.h" 00010 00011 #ifdef WITH_TESTING 00012 # include "tests.h" 00013 #endif 00014 00015 /////////////// structs ///////////////// 00016 00017 struct UserInput { 00018 Direction d; 00019 float mag; 00020 }; 00021 00022 /////////////// objects /////////////// 00023 00024 N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11); 00025 Gamepad pad; 00026 BreakoutEngine breakout; 00027 SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS 00028 Serial serial(USBTX, USBRX); // for PC debug 00029 00030 ///////////// prototypes /////////////// 00031 00032 void init(); 00033 void update_game(UserInput input); 00034 void render(); 00035 void main_menu(); 00036 void settings(); 00037 void how_to_play(); 00038 void loss_screen(); 00039 void victory_screen(); 00040 void title_screen(); 00041 void main_game(); 00042 void flash_screen(N5110 &lcd); 00043 void countdown(); 00044 void save_hi_score(int hi_score); 00045 int get_hi_score(); 00046 bool compare_to_hi_score(int score); 00047 void print_hi_score(int col,int row); 00048 void flash_hi_score_screen(); 00049 void reset_victory(int score, int bonus); 00050 void reset_loss(); 00051 00052 Bitmap breakwhite(breakwhite_data, 48, 84); // assign the title screen sprites 00053 Bitmap breakblack(breakblack_data, 48, 84); 00054 Bitmap arrowup(arrowup_data, 5, 7); // assign the arrow up sprite data 00055 Bitmap arrowdown(arrowdown_data, 5, 7); // assign the arrow down sprite data 00056 Bitmap three(three_data, 48, 84); // assign the 3 sprite data 00057 Bitmap two(two_data, 48, 84); // assign the 2 sprite data 00058 Bitmap one(one_data, 48, 84); // assign the 1 sprite data 00059 00060 bool tilt = false; 00061 float sens = 0.5; // default sens 00062 int number_of_frames = 0; // tracks the number of frames passed to use for bonus score 00063 00064 ///////////// functions //////////////// 00065 00066 int main() 00067 { 00068 00069 #ifdef WITH_TESTING 00070 int number_of_failures = run_all_tests(); 00071 00072 if(number_of_failures > 0) return number_of_failures; 00073 #endif 00074 00075 init(); // initialise the gamepad 00076 title_screen(); // run the title screen 00077 } 00078 00079 00080 00081 00082 void init() // initialies all classes and libraries 00083 { 00084 // need to initialise LCD and Gamepad 00085 lcd.init(); 00086 pad.init(); 00087 breakout.init(PADDLE_WIDTH,PADDLE_HEIGHT,BALL_SIZE,BALL_SPEED); // init the objects 00088 } 00089 00090 void render() // draws each frame on the LCD 00091 { 00092 // clear screen, re-draw and refresh 00093 lcd.clear(); 00094 breakout.draw(lcd); 00095 lcd.refresh(); 00096 } 00097 00098 00099 //////////// MENUING & GAME LOOP FUNCTIONS ////////////////// 00100 00101 00102 void title_screen() 00103 { 00104 tilt = false; // reset the tilt variable so that on start, joystick is default 00105 breakout.reset_mult(); 00106 lcd.clear(); 00107 00108 lcd.setBrightness(1); // stops the game from dimming (hardware bug?) 00109 00110 breakblack.render(lcd, 0, 0); // render the first frame 00111 lcd.refresh(); 00112 pad.leds_off(); 00113 wait(0.5); 00114 00115 pad.reset_flags(); 00116 00117 while (pad.check_event(Gamepad::START_PRESSED) == false) { // while start is not pressed alternate sprites 00118 00119 lcd.clear(); 00120 00121 breakwhite.render(lcd, 0, 0); 00122 lcd.refresh(); 00123 pad.leds_on(); 00124 wait(0.5); 00125 00126 lcd.clear(); 00127 00128 breakblack.render(lcd, 0, 0); 00129 lcd.refresh(); 00130 pad.leds_off(); 00131 wait(0.5); 00132 } 00133 00134 pad.tone(750.0,0.3); 00135 wait(0.2); 00136 main_menu(); // load main menu 00137 } 00138 00139 00140 void main_menu() 00141 { 00142 lcd.setBrightness(1); // fixes random screen dimming (hardware bug?) 00143 00144 lcd.clear(); 00145 lcd.printString(" START ",0,1); // start game with default as joystick 00146 lcd.printString(" SETTINGS ",0,2); // choose between joystick and tilt 00147 lcd.printString(" HOW TO PLAY ",0,3); // brief text on how to interact with the game 00148 lcd.printString("HI-SCORE: ",0,5); 00149 print_hi_score(55,5); 00150 lcd.refresh(); 00151 wait(0.3); // load initial frame 00152 00153 pad.reset_flags(); // manually resets all button flags which fixes button bounce and prevents inputs carrying through to different menus 00154 pad.leds_off(); // prevents hardware bug where right most led flickers 00155 00156 int pointer = 1; 00157 00158 while (pad.check_event(Gamepad::A_PRESSED) == false) { 00159 lcd.clear(); 00160 lcd.printString(" START ",0,1); // start game with default as joystick 00161 lcd.printString(" SETTINGS ",0,2); // choose between joystick and tilt 00162 lcd.printString(" HOW TO PLAY ",0,3); // brief text on how to interact with the game 00163 lcd.printString("HI-SCORE: ",0,5); 00164 print_hi_score(55,5); 00165 lcd.printString(" >",0,pointer); 00166 lcd.refresh(); 00167 wait(0.1); 00168 if (pad.get_direction() == N && pointer > 1) { // if L is pressed and pointer isnt already on START, move it up one line 00169 pointer -= 1; 00170 pad.tone(750.0,0.3); 00171 wait(0.1); 00172 } else if (pad.get_direction() == S && pointer < 3) { // if R is pressed and pointer isnt already on HOW TO PLAY, move it down one line 00173 pointer += 1; 00174 pad.tone(750.0,0.3); 00175 wait(0.1); 00176 } 00177 if (pad.check_event(Gamepad::X_PRESSED) & pad.check_event(Gamepad::Y_PRESSED)) { 00178 save_hi_score(0); // resets hi score 00179 } 00180 //printf("Pointer 1 = %d",pointer); 00181 00182 } 00183 if (pointer == 1) { // if START was selected on exit of the while loop, run main game with the appropriate tilt/joystick setting 00184 pad.tone(750.0,0.3); 00185 number_of_frames = 0; 00186 main_game(); 00187 } else if (pointer == 2) { // if SETTINGS was selected, enter the settings menu 00188 pad.tone(750.0,0.3); 00189 settings(); 00190 } else if (pointer == 3) { // if HOW TO PLAY was selected, display instructions on how to play 00191 pad.tone(750.0,0.3); 00192 how_to_play(); 00193 } 00194 } 00195 00196 void settings() 00197 { 00198 lcd.clear(); // load initial frame 00199 lcd.printString(" JOYSTICK ",0,1); // choose joystick 00200 lcd.printString(" TILT ",0,2); // choose tilt 00201 lcd.printString("SENS :",0,4); 00202 lcd.drawRect(42,30, 40,10,FILL_TRANSPARENT); 00203 lcd.drawRect(42,30,40 * pad.read_pot() + 1,10,FILL_BLACK); // represents the sensitivity which is changed by turning the pot 00204 lcd.refresh(); 00205 wait(0.1); 00206 00207 pad.reset_flags(); // fixes button bounce 00208 00209 int pointer = 1; // init the pointer 00210 00211 while (pad.check_event(Gamepad::B_PRESSED) == false) { // while B is not pressed to return to main menu 00212 lcd.clear(); 00213 lcd.printString(" JOYSTICK ",0,1); // choose joystick 00214 lcd.printString(" TILT ",0,2); // choose tilt 00215 lcd.printString("SENS :",0,4); 00216 lcd.printString(" >",0,pointer); 00217 lcd.drawRect(42,30, 40,10,FILL_TRANSPARENT); 00218 lcd.drawRect(42,30,40 * pad.read_pot() + 1,10,FILL_BLACK); // have it so it fills half the transparent one (default position) 00219 lcd.refresh(); 00220 wait(0.1); 00221 if (pad.get_direction() == N && pointer > 1) { // if L is pressed and pointer isnt already on JOYSTICK, move it up one line 00222 pointer -= 1; 00223 pad.tone(750.0,0.3); 00224 wait(0.1); 00225 } else if (pad.get_direction() == S && pointer < 2) { // if R is pressed and pointer isnt already on TILT, move it down one line 00226 pointer += 1; 00227 pad.tone(750.0,0.3); 00228 wait(0.1); 00229 } 00230 00231 if (pad.check_event(Gamepad::A_PRESSED)) { // if A is pressed, switch the tilt option accordingly 00232 pad.tone(750.0,0.3); 00233 wait(0.1); 00234 if (pointer == 1) { // if A is pressed on JOYSTICK, tilt = false 00235 tilt = false; 00236 } else if (pointer == 2) { // if A is pressed on TILT, tilt == true 00237 tilt = true; 00238 } 00239 } 00240 00241 if (pad.check_event(Gamepad::B_PRESSED)) { // when B is pressed return to main menu 00242 pad.tone(750.0,0.3); 00243 sens = pad.read_pot() + 0.5f; // sens is set as the pot value at the instant the settings menu is exited +the minimum value of 0.5 00244 breakout.set_paddle_motion(tilt,sens); // sets the paddles motion options 00245 //printf("Sensitivity = %d",sens); 00246 wait(0.3); 00247 main_menu(); 00248 } 00249 //printf("Pointer 2 = %d",pointer); 00250 } 00251 } 00252 00253 void how_to_play() // explains how to interact with the game 00254 { 00255 lcd.clear(); 00256 lcd.printString(" B = LASER ",0,0); 00257 lcd.printString(" START = PAUSE ",0,1); 00258 lcd.printString(" DESTROY ALL ",0,2); 00259 lcd.printString(" BRICKS. ",0,3); 00260 arrowdown.render(lcd, 38, 43); 00261 lcd.refresh(); 00262 wait(0.1); // load initial frame 00263 00264 pad.reset_flags(); // fixes button bounce 00265 00266 while (pad.check_event(Gamepad::B_PRESSED) == false) { // while B is not pressed to return to main menu, display instruction on how to interact with the game 00267 00268 if (pad.get_direction() == S) { 00269 lcd.clear(); 00270 lcd.printString(" CONTINUE TO ",0,2); 00271 lcd.printString("INCREASE SCORE. ",0,3); 00272 lcd.printString(" BONUS SCORE ",0,4); 00273 lcd.printString("BASED ON TIME. ",0,5); 00274 arrowup.render(lcd, 38, 0); 00275 lcd.refresh(); 00276 wait(0.1); 00277 } 00278 if (pad.get_direction() == N) { 00279 lcd.clear(); 00280 lcd.printString(" B = LASER ",0,0); 00281 lcd.printString(" START = PAUSE ",0,1); 00282 lcd.printString(" DESTROY ALL ",0,2); 00283 lcd.printString(" BRICKS ",0,3); 00284 arrowdown.render(lcd, 38, 43); 00285 lcd.refresh(); 00286 wait(0.1); 00287 } 00288 } 00289 wait(0.3); 00290 main_menu(); // when B is pressed, the loop is exited and main menu is entered once again 00291 } 00292 00293 00294 void main_game() // the Game loop 00295 { 00296 pad.reset_flags(); // fixes button bounce 00297 00298 int fps = 8; // frames per second 00299 bool pause = false; // set pause screen to false 00300 //printf("Pause = %d",pointer); 00301 00302 countdown(); // run the countdown 00303 00304 render(); // first draw the initial frame 00305 wait(1.0f/fps); // and wait for one frame period 00306 00307 00308 // game loop - read input, update the game state and render the display 00309 while (1) { 00310 breakout.read_input(pad); // read input from pad 00311 breakout.update(pad); // update game 00312 lcd.setBrightness(1); // stops the game from dimming (bug) 00313 render(); // draw new frame 00314 00315 if (breakout.check_loss(pad) == true) { // if life lost flash screen 00316 flash_screen(lcd); 00317 } 00318 if (pad.check_event(Gamepad::START_PRESSED)) { // if BACK pressed, toggle pause 00319 pause = !pause; 00320 pad.reset_flags(); // fixes button bounce? 00321 } 00322 00323 while (pause == true) { // if pause is true, display pause screen 00324 lcd.clear(); 00325 lcd.printString(" PAUSED ",0,1); 00326 lcd.printString(" START = PLAY",0,3); 00327 lcd.printString(" BACK = MENU",0,4); 00328 lcd.refresh(); 00329 wait(0.1); 00330 if (pad.check_event(Gamepad::START_PRESSED)) { // if START pressed, toggle pause, leaving pause screen 00331 pause = !pause; 00332 } 00333 if (pad.check_event(Gamepad::BACK_PRESSED)) { // if BACK pressed, return to the title screen 00334 reset_loss(); 00335 title_screen(); 00336 } 00337 } 00338 00339 if (breakout.get_paddle_lives() == 0) { // when all lives lost, enter loss screen 00340 pad.leds_off(); //turns last led off (doesnt run through and update board so last led doent turn off via lives leds 00341 loss_screen(); 00342 } 00343 00344 if (breakout.get_num_left() == 0) { // when all bricks destroyed, display victory screen 00345 victory_screen(); 00346 } 00347 number_of_frames ++; // track the number of frames passed to add to the score (inversely proportional) 00348 wait(1.0f/fps); // wait for 1 frame 00349 } 00350 } 00351 00352 00353 void loss_screen() // loss screen when lives of paddle == 0 00354 { 00355 if (compare_to_hi_score(breakout.get_score()) == true) { // little hi-score sequence if current score is higher than prev 00356 flash_hi_score_screen(); 00357 } 00358 00359 lcd.clear(); 00360 char buffer[14]; // init the buffer 00361 sprintf(buffer,"%2d",breakout.get_score()); // print the score to the buffer 00362 lcd.printString(buffer,WIDTH/2 - 12,2); // print buffer on lcd 00363 lcd.printString(" RESTART? ",2,1); 00364 lcd.printString(" PRESS START ",1,4); 00365 lcd.refresh(); 00366 pad.tone(750.0,0.3); 00367 wait(0.4); 00368 00369 pad.tone(300.0,0.3); 00370 wait(0.4); 00371 00372 pad.reset_flags(); 00373 00374 while (pad.check_event(Gamepad::START_PRESSED) == false) { // flashes the score, waits for START to return to title screen 00375 lcd.clear(); 00376 00377 lcd.printString(" RESTART? ",2,1); 00378 lcd.printString(" PRESS START ",1,4); 00379 lcd.refresh(); 00380 00381 wait(0.4); 00382 00383 lcd.clear(); 00384 00385 lcd.printString(buffer,WIDTH/2 - 12,2); 00386 lcd.printString(" RESTART? ",2,1); 00387 lcd.printString(" PRESS START ",1,4); 00388 lcd.refresh(); 00389 00390 wait(0.4); 00391 } 00392 reset_loss(); 00393 title_screen(); 00394 } 00395 00396 00397 void victory_screen() // victory screen when all bricks are destroyed 00398 { 00399 int bonus = NULL; 00400 00401 if (breakout.get_score()/2 - ((breakout.get_score()/2) * number_of_frames)/720 > 0) { // beat within 90 seconds (8 fps) and you get a bonus 00402 bonus = breakout.get_score()/2 - ((breakout.get_score()/2) * number_of_frames)/720; 00403 } else { 00404 bonus = 0; // else you get no bonus 00405 } 00406 00407 if (compare_to_hi_score(bonus+breakout.get_score()) == true) { // little hi-score sequence if current score is higher than prev 00408 flash_hi_score_screen(); 00409 } 00410 00411 lcd.clear(); 00412 00413 char buffer1[14]; 00414 sprintf(buffer1,"%2d",breakout.get_score()); 00415 lcd.printString(buffer1,WIDTH/2 - 12,2); 00416 00417 char buffer2[14]; 00418 sprintf(buffer2,"%2d",bonus); 00419 lcd.printString(buffer2,WIDTH/2 + 12,3); 00420 lcd.printString(" BONUS: ",2,3); 00421 00422 lcd.printString(" VICTORY! ",2,0); 00423 lcd.printString(" CONT = START ",0,4); 00424 lcd.printString(" MENU = BACK ",0,5); 00425 lcd.refresh(); 00426 pad.tone(2500.0,0.1); 00427 wait(0.4); 00428 00429 pad.tone(2500.0,0.1); 00430 wait(0.2); 00431 00432 pad.tone(4000.0,0.6); 00433 wait(0.6); 00434 00435 pad.reset_flags(); 00436 00437 while (pad.check_event(Gamepad::START_PRESSED) || pad.check_event(Gamepad::BACK_PRESSED) == false) { // while neither START or BACK is pressed, flash the score and display options 00438 lcd.clear(); 00439 00440 lcd.printString(" VICTORY! ",2,0); 00441 lcd.printString(" CONT = START ",0,4); 00442 lcd.printString(" MENU = BACK ",0,5); 00443 00444 lcd.refresh(); 00445 00446 wait(0.4); 00447 00448 lcd.clear(); 00449 00450 lcd.printString(buffer1,WIDTH/2 - 12,2); 00451 lcd.printString(buffer2,WIDTH/2 + 12,3); 00452 lcd.printString(" BONUS:",2,3); 00453 00454 lcd.printString(" VICTORY! ",2,0); 00455 lcd.printString(" CONT = START ",0,4); 00456 lcd.printString(" MENU = BACK ",0,5); 00457 lcd.refresh(); 00458 00459 pad.tone(2500.0,0.1); 00460 00461 lcd.refresh(); 00462 00463 wait(0.4); 00464 00465 if (pad.check_event(Gamepad::START_PRESSED)) { 00466 reset_victory(breakout.get_score(),bonus); // reset game 00467 main_game(); // reload game 00468 } else if (pad.check_event(Gamepad::BACK_PRESSED)) { 00469 reset_loss(); // reset game 00470 title_screen(); // load title screen 00471 } 00472 } 00473 } 00474 00475 00476 void flash_screen(N5110 &lcd) // flash the screen when a life is lost 00477 { 00478 lcd.setBrightness(0); 00479 wait(0.1); 00480 lcd.setBrightness(1); 00481 wait(0.1); 00482 lcd.setBrightness(0); 00483 wait(0.1); 00484 lcd.setBrightness(1); 00485 wait(0.1); 00486 lcd.setBrightness(0); 00487 wait(0.1); 00488 lcd.setBrightness(1); 00489 wait(0.1); 00490 lcd.setBrightness(0); 00491 wait(0.1); 00492 lcd.setBrightness(1); 00493 } 00494 00495 void countdown() // draw the countdown 00496 { 00497 lcd.setBrightness(1); // stops the game from dimming (bug) 00498 00499 lcd.clear(); 00500 three.render(lcd, 0, 0); // render the 3 00501 lcd.refresh(); 00502 pad.tone(500.0,0.5); 00503 wait(1); // wait 1 second 00504 00505 lcd.setBrightness(1); 00506 00507 lcd.clear(); 00508 two.render(lcd, 0, 0); // render 2 00509 lcd.refresh(); 00510 pad.tone(500.0,0.5); 00511 wait(1); // wait 1 second 00512 00513 lcd.setBrightness(1); 00514 00515 lcd.clear(); 00516 one.render(lcd, 0, 0); // render 1 00517 lcd.refresh(); 00518 pad.tone(1000.0,1); 00519 wait(1); // wait 1 second 00520 } 00521 00522 00523 //////////////// SD CARD FUNCTIONS //////////////////////// 00524 00525 00526 void save_hi_score(int hi_score) // save score to SD card 00527 { 00528 serial.baud(115200); // max speed 00529 FILE *fp; // file pointer 00530 fp = fopen("/sd/hi_score.txt", "w"); 00531 if (fp == NULL) { // if it can't open the file then print error message 00532 serial.printf("Error\n"); 00533 } else { // opened file so can write 00534 fprintf(fp, "%d",hi_score); 00535 serial.printf("Written to file.\n"); 00536 fclose(fp); // close the file after writing 00537 } 00538 } 00539 00540 00541 int get_hi_score() // retrieve score from SD card 00542 { 00543 serial.baud(115200); // max speed 00544 FILE *fp; 00545 fp = fopen("/sd/hi_score.txt", "r"); 00546 int stored_hi_score = NULL; 00547 if (fp == NULL) { // if it can't open the file then print error message 00548 serial.printf("Error\n"); 00549 } else { // opened file so can write 00550 fscanf(fp, "%d",&stored_hi_score); 00551 serial.printf("Read %d from file.\n",stored_hi_score); 00552 fclose(fp); // close the file after reading 00553 } 00554 return stored_hi_score; // returns the stored hi score 00555 } 00556 00557 00558 bool compare_to_hi_score(int score) // returns true if new score higher than current stored hi score 00559 { 00560 if (score >= get_hi_score()) { 00561 //printf("hi score! \n"); 00562 save_hi_score(score); // writes the new score to the SD card 00563 return true; 00564 } else { 00565 return false; 00566 } 00567 } 00568 00569 00570 void print_hi_score(int col,int row) // print hi score to lcd at specified location 00571 { 00572 char buffer[14]; // creates buffer 00573 sprintf(buffer,"%2d",get_hi_score()); // puts hi-score in buffer 00574 lcd.printString(buffer,col,row); // prints buffer to the screen 00575 00576 } 00577 00578 00579 void reset_loss() // reset the game when returning to title screen from any point 00580 { 00581 breakout.reset_paddle_lives(); // resets lives back to 6 00582 breakout.set_prev_score(0); // resets prev score to 0 00583 number_of_frames = 0; // reset the number of frames 00584 breakout.reset_mult(); // reset multiplier 00585 breakout.reset_game(); // return game to initial positions 00586 } 00587 00588 00589 void reset_victory(int score, int bonus) // reset the game after a victory 00590 { 00591 breakout.set_prev_score(score + bonus); // saves score 00592 number_of_frames = 0; // reset the number of frames 00593 breakout.inc_mult(); // increment multiplier 00594 breakout.reset_game(); // return game to initial positions 00595 } 00596 00597 00598 void flash_hi_score_screen() // flash the hi score, called when hi score acheieved 00599 { 00600 lcd.clear(); 00601 lcd.printString(" NEW ",0,2); 00602 lcd.printString(" HI-SCORE! ",0,3); 00603 lcd.refresh(); 00604 00605 pad.tone(2500.0,0.2); 00606 wait(0.2); 00607 00608 pad.tone(4000.0,0.4); 00609 wait(1); 00610 00611 lcd.clear(); 00612 print_hi_score(30,3); 00613 lcd.refresh(); 00614 00615 pad.tone(2500.0,0.2); 00616 wait(0.2); 00617 00618 pad.tone(4000.0,0.4); 00619 wait(1); 00620 00621 lcd.clear(); 00622 lcd.printString(" NEW ",0,2); 00623 lcd.printString(" HI-SCORE! ",0,3); 00624 lcd.refresh(); 00625 00626 pad.tone(2500.0,0.2); 00627 wait(0.2); 00628 00629 pad.tone(4000.0,0.4); 00630 wait(1); 00631 00632 lcd.clear(); 00633 print_hi_score(30,3); 00634 lcd.refresh(); 00635 00636 pad.tone(2500.0,0.2); 00637 wait(0.2); 00638 00639 pad.tone(4000.0,0.4); 00640 wait(1.3); 00641 }
Generated on Thu Jul 14 2022 01:22:29 by 1.7.2