Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 Wed Jul 13 2022 09:05:52 by
1.7.2