James Cummins / Mbed 2 deprecated el17jnc

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002 ELEC2645 Embedded Systems Project
00003 School of Electronic & Electrical Engineering
00004 University of Leeds
00005 Name: James Nathan Cummins
00006 Username: el17jnc
00007 Student ID Number: 201096364
00008 Date: 22/03/19
00009 */
00010 
00011 #include "Gamepad.h"
00012 #include "mbed.h"
00013 #include "N5110.h"
00014 #include "BrickBreakerEngine.h"
00015 #include "ClassicEngine.h"
00016 #include "OptionsEngine.h"
00017 #include "SDFileSystem.h"
00018 
00019 #ifdef WITH_TESTS
00020 #include "tests.h"
00021 #endif
00022 
00023 #define RADIUS 3
00024 
00025 
00026 //Objects
00027 Gamepad gamepad;
00028 N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
00029 ClassicEngine classic;
00030 BrickBreakerEngine brick;
00031 OptionsEngine opt;
00032 Map map;
00033 AnalogIn randnoise(PTB0);
00034 FXOS8700CQ accelerometer(I2C_SDA,I2C_SCL);
00035 Ball ball;
00036 Pause pause;
00037 SDFileSystem sd(PTE3,PTE1,PTE2,PTE4,"sd");
00038 
00039 /** Enum for start menu options*/
00040 enum StartOption{
00041     CLASSIC,
00042     BRICKBREAKER,
00043     OPTIONS
00044     };
00045 
00046 /**Start selection struct*/
00047 struct StartSelection{
00048     int output;                 /**<Integer output for line to print arrows to*/
00049     StartOption next_state[3];  /**<Array of enums for possible next start option*/
00050     };
00051 
00052 //Methods
00053 void startscreen();
00054 StartOption menu();
00055 void init();
00056 void print_start_menu(int output);
00057 void classic_mode();
00058 void brickbreaker_mode();
00059 void options_menu();
00060 
00061 
00062 ////////////////Main Function/////////////////
00063 
00064 int fps = 16;   //declared globally so it doesn't have to be passed to
00065                 //the different game mode functions
00066 int main(){
00067     init();             //first initialise all objects   
00068      
00069 #ifdef WITH_TESTS                                   //run tests to check code is correct
00070     int test_failures = no_of_tests_failed();
00071     if(test_failures > 0) return test_failures;      //main function returns no of failures
00072 #endif
00073 
00074     startscreen();      //then display the introductory screen
00075     while(1){                //keep game running until power is removed
00076         StartOption choice_selected = menu();           //get which mode user wants from the start menu
00077         if(choice_selected == CLASSIC){ classic_mode();}                        //jump to a game mode once
00078         if(choice_selected == BRICKBREAKER){ brickbreaker_mode();}              //its respective enum is received
00079         if(choice_selected == OPTIONS){ options_menu();}                        //from the start menu
00080     }
00081 }
00082   
00083   
00084   
00085 //////////////Start up functions///////////////////
00086 
00087 void init(){                    //initialise all objects in the game
00088     gamepad.init();
00089     lcd.init();                 //some objects are initialised again elsewhere
00090     lcd.setContrast(0.55);      //e.g. to reset a game mode when restart is pressed
00091     classic.init(ball, map);
00092     brick.init(RADIUS, ball);
00093     opt.init();
00094     map.init();
00095     pause.init();
00096     accelerometer.init();
00097     sd.disk_initialize();
00098     wait(1);
00099 }
00100     
00101 void startscreen() {
00102     lcd.clear();
00103     char gamename[] = {'L', 'A', 'B', 'Y', 'R', 'I', 'N', 'T', 'H', ' ', ' ', '\0'};    //char array containing the game title
00104     int i = 0;
00105     for(int a = 0; a < 35; a++){        //from first letter position to end of the screen at 2 pixel intervals
00106         lcd.clear();
00107         lcd.drawCircle(24+2*a, 21, 3, FILL_BLACK);      //move the ball 2 pixels at a time
00108         for (i = 0; i < a/3; i++) {
00109             lcd.printChar(gamename[i], 15+i*6, 2);      //print the next letter in game title once the ball has moved past
00110             lcd.refresh();                              //display all contents on LCD display
00111             }
00112         wait_ms(50);
00113     }
00114     lcd.printString("Press start", 9, 4);       //instruct user how to advance
00115     lcd.printString("to play >", 15, 5);
00116     lcd.refresh(); 
00117     bool advance = false;
00118     while (!advance){                                       //check for user advancing
00119         if (gamepad.check_event(gamepad.START_PRESSED)){
00120             lcd.clear();        //if user presses start, clear screen
00121             lcd.refresh();      //before advancing to start menu
00122             advance = true;
00123             }
00124         else { advance = false; }
00125     }
00126 }
00127 
00128 StartOption menu(){    
00129     StartSelection fsm[3] = {       //state machine to power start menu
00130         {0,{OPTIONS,BRICKBREAKER,CLASSIC}},     //next_state[0] always holds the option above the current one
00131         {2,{CLASSIC,OPTIONS,BRICKBREAKER}},     //next_state[1] always holds the option below the current one
00132         {4,{BRICKBREAKER,CLASSIC,OPTIONS}}      //next_state[2] always holds the current option
00133     };
00134     StartOption state = CLASSIC;  //start with the arrow on the top option
00135     int next = 2;  //next_state = 2 so that by default it doesn't change arrow position
00136     while(!(gamepad.check_event(gamepad.A_PRESSED))){     //select choice with A
00137         state = fsm[state].next_state[next];
00138         lcd.clear();
00139         if(gamepad.get_direction() == N){ next = 0;}            //move arrow up
00140         else if(gamepad.get_direction() == S){ next = 1;}       //move arrow down
00141         else {next = 2;}                                        //keep arrow in same position
00142         print_start_menu(fsm[state].output);    //print on LCD display
00143         lcd.refresh();
00144         wait(0.25);     //longer wait than 1/fps to reduce the impact of button bounce
00145     }
00146     lcd.clear();
00147     lcd.refresh();      //clear display before moving on to a game mode
00148     return state;       //tell main which game mode to run
00149 }
00150 
00151 void print_start_menu(int output){
00152         lcd.printString(">", 0, output);
00153         lcd.printString("Classic", 36, 0);
00154         lcd.printString("BrickBreak", 18, 2);
00155         lcd.printString("Options", 36, 4);
00156         lcd.printString("(A = Select)", 12, 5);
00157 }
00158 
00159 //////////////////Game Mode Functions////////////////////////////////
00160 
00161 void classic_mode(){
00162     classic.init(ball, map);
00163     pause.classic_help(gamepad, lcd);       //display how to play instructions before start of game
00164     bool collision = false;                 //used to determine whether to keep iterating or not
00165     while(!(collision)){
00166         classic.classic_update(ball, accelerometer, map);       //methods to update the game
00167         lcd.clear();                                            //and render it as the user plays
00168         classic.classic_draw(lcd, map, ball);
00169         lcd.refresh();
00170         wait(1/fps);
00171         if(gamepad.check_event(gamepad.BACK_PRESSED)){                  //check for use of the pause menu
00172             PauseOption choice = pause.pause_menu(gamepad, lcd, fps);   //retrieve user's input
00173             if(choice == RESUME){}                                          //the different options must be processed
00174             if(choice == RESTART){ classic.init(ball, map); }               //in main.cpp as they have different 
00175             if(choice == QUIT){ break; }                                    //return types so can't be passed into main
00176             if(choice == HELP){ pause.classic_help(gamepad, lcd); }         //by one public method in pause.h
00177         }
00178         if(classic.finished()){         //check if the game has been completed
00179             classic.mode_complete(lcd, gamepad, fps);       //display time taken and break from game mode
00180             break;
00181         }
00182         if(map.check_wall_collision(gamepad, ball)){    //end the game if collision with wall
00183             collision = classic.mode_failed(lcd, gamepad, ball, map);   //gives the option to restart the game (and stay in while loop) or quit
00184             if(!(collision)){ classic.init(ball, map); }
00185         }
00186     }
00187 }
00188 
00189 void brickbreaker_mode(){
00190     pause.brickbreaker_help(gamepad, lcd);      //display instructions before start of game
00191     for(int i = 0; i < 45*fps; i++){
00192         if(i == 1){ brick.set_score(0); }       //reset score when game restarts 
00193         ball.read_input(accelerometer);         //methods to continue updating and rendering the game
00194         ball.update();
00195         /*Vector2D position = _ball.get_position();
00196         printf("ball_x = %f | ball_y = %f\n", position.x, position.y);  //note: running with tests causes the game to run slow and take ~2min30s*/
00197         brick.check_square_collision(randnoise, ball);
00198         lcd.clear();
00199         brick.brickbreaker_draw(lcd, ball);
00200         lcd.refresh();
00201         wait_ms(1000/fps);
00202         if(gamepad.check_event(gamepad.BACK_PRESSED)){                      //check for use of the pause menu
00203             PauseOption choice = pause.pause_menu(gamepad, lcd, fps);       //Get the user's selection
00204             i = pause.brickbreaker_action(choice, gamepad, lcd, i, fps);    //returns which frame to jump to
00205         }
00206         brick.time_warning(gamepad, i, fps);    //Use LEDs to display how much time is left
00207     }
00208     brick.end(gamepad, lcd);                    //display the 'time up' screen with the user score
00209     brick.write_high_scores();                  //update high scores accordingly
00210 }
00211 
00212 void options_menu(){
00213     Option choice = BRIGHTNESS;     //variable to store the selected option initialised to the top item in list
00214     while(!(gamepad.check_event(gamepad.A_PRESSED))){
00215         lcd.clear();                                    //keep rendering and updating the position of the
00216         opt.display_options(lcd);                       //menu arrows until a choice is made
00217         choice = opt.option_selection(gamepad, lcd);
00218         lcd.refresh();
00219         wait(0.2);
00220     }
00221     if(choice == BRIGHTNESS){ opt.change_brightness(gamepad, lcd); }            //each menu option called by its
00222     if(choice == BALL_SPEED){ opt.change_ball_speed(gamepad, lcd, ball); }      //respective enum and a method in
00223     if(choice == HIGH_SCORES){ opt.view_high_scores(gamepad, lcd); }            //options engine processes the option
00224 }
00225 
00226