Ellis Blackford Stroud 201155309

Dependencies:   mbed FATFileSystem

Menu/Menu.cpp

Committer:
ellisbhastroud
Date:
2019-05-09
Revision:
17:98127ac75195
Parent:
16:c8d68cbd1ae2

File content as of revision 17:98127ac75195:

#include "Menu.h"

// constructor

Menu::Menu()
{

}

//deconstructor

Menu::~Menu()
{

}

//public methods

void Menu::init() //class variables automatically set here
{
    reset_start_game_flag(); //resets start flag to make sure game enters menu loop when first run
    _cursor_pos = 0; //cursor begins on position 0
    _frame_rate = 40; //frame rate, contrast and brightness can be changed in settings
    _contrast = 0.55f;
    _brightness = 1.0f; //full brightness makes ball easier to see when moving

}

void Menu::welcome_loop(Gamepad &pad, N5110 &lcd) //prints welcome screen
{   
    while(pad.check_event(Gamepad::START_PRESSED) == false) {
        lcd.clear();
        pad.leds_off();
        lcd.drawSprite(0, 4, 15, 60, (int *)mini_logo);
        lcd.drawSprite(22, 21, 15, 60, (int *)golf_logo);
        lcd.refresh();
        wait(0.3);
        lcd.clear();
        pad.leds_on();
        lcd.drawSprite(0, 6, 15, 60, (int *)mini_logo);
        lcd.drawSprite(24, 21, 15, 60, (int *)golf_logo);        
        lcd.printString("PRESS START",12,5);
        lcd.refresh();
        wait(0.3);
    }
    pad.tone(659.25 , 0.25); //play note (E5)
    lcd.setBrightness(_brightness); //set brightness to 100% to counter tone function messing with screen backlight 
}

void Menu::menu_loop(Gamepad &pad, N5110 &lcd) //prints menu creen and controls cursor and choices
{
    while(pad.check_event(Gamepad::START_PRESSED) == false){ //loop until start and next screen chosen
        
        lcd.clear();
        lcd.printString("START GAME",10,1);
        lcd.printString("HIGHSCORES",10,3);
        lcd.printString("SETTINGS",10,5);
        read_input(pad);
        move_cursor(lcd);
        lcd.refresh();
        wait(0.2);
    }
    pad.tone(523.25, 0.1); //play note when button pressed (middle C) - buzzer effects frequency of pwn pins which changes brightness
    change_screen();                                                
}

void Menu::start_loop(Gamepad &pad, N5110 &lcd) //prints start screen and returns true when game started
{
    while(pad.check_event(Gamepad::A_PRESSED) == false) { //flashes leds and displays messaged until a pressed and game begins
        lcd.clear();
        pad.leds_on(); //turns gamepad leds on
        lcd.printString(" PRESS A ",16,2);
        lcd.printString(" TO START!",14,3);
        lcd.refresh();
        wait(0.3);
        pad.leds_off(); //turns gamepad leds off
        lcd.clear();
        lcd.refresh();
        wait(0.3);
    }
    _start_game_flag = true; //this causes code to enter main game loop
    pad.tone(659.25 , 0.25); //play note (E5)
    lcd.clear();
}

void Menu::highscores_loop(Gamepad &pad, N5110 &lcd, SDFileSystem &sd) //highscores screen loop
{ 
    sd_read(sd); //reads values from highscores.txt file into array and sorts in ascending order
    while(pad.check_event(Gamepad::BACK_PRESSED) == false) {   //loops until back pressed
    
        lcd.clear();
        lcd.printString("HIGHSCORES",13,0);
    
        for(int i = 0; i < _n ; i++) { //displays highscores
            char buffer[14];
            sprintf(buffer,"%i - %i", i + 1, _highscores_array[i]); //prints values from highscores array
            lcd.printString(buffer,0,i+1);
        }

        lcd.refresh();
    }
    pad.tone(392.00 , 0.25); //play note (G4)
    _start_game_flag = false; //this causes code to return back to main menu loop
}

void Menu::settings_loop(Gamepad &pad, N5110 &lcd)//prints settings screen
{   
    _cursor_pos = 0;        
    while(pad.check_event(Gamepad::BACK_PRESSED) == false) { //loops until back button pressed
      
        lcd.clear();
        drawSettings(lcd); //draws settings paramters and changes value according to cursor position and potentiometer input
        move_cursor(lcd); //moves cursor according to joystick position
        lcd.refresh();
        wait(0.2);
        read_input(pad); //reads joystick and pot inputs 
    }
    pad.tone(392.00 , 0.25); //play note (G4)
    _start_game_flag = false; //this causes code to return back to main menu loop
}

int Menu::get_frame_rate() //returns frame rate 5-50
{
    int frame_rate = _frame_rate;
    return frame_rate;
}

float Menu::get_brightness() //returns brightness private variable from class
{
    return _brightness;    
}

bool Menu::get_start_game_flag()  //returns start game flag
{
    return _start_game_flag;
}

void Menu::reset_start_game_flag() //resets start game flag to false
{
    _start_game_flag = false;    
}

MenuChoice Menu::get_screen() //gets screen choice
{
    return _screen;    
}

//private methods

void Menu::read_input(Gamepad &pad) //Reads input from gamepad into class variables
{
    _joy_direction  = pad.get_direction(); //joystick direction 
    _pot = pad.read_pot(); //potentiometer value 0-1 float

}

void Menu::sd_read(SDFileSystem &sd) //reads values from highscores file into array
{
    FILE *fp;
    fp = fopen("/sd/highscores.txt", "r"); //open highscores.txt file for reading
    if(!(fp == NULL)) { //if file is opened
        
        int n = 0;  //no. of line stored in this

        while (fscanf(fp, "%*d") != EOF) { //counts number of lines until reach EOF (end of file)
            n++;  // increment counter when read a line
        }
        _highscores_array = (int *)calloc(n, sizeof (int)); //creates array of length n and initialises to 0
        _n = n; //number of values in array - used when displaying highscores

        int i=0;
        rewind(fp); //return to beginning of file
    
        while (fscanf(fp, "%d",&_highscores_array[i]) != EOF) { //read into array
            i++;  // read data into array and increment index
        }
        fclose(fp);  //close file
        
        sort(_highscores_array, _highscores_array + n); //sorts array in ascending order - the lowest scores are top.

        
    } else { //if file does not open
         _highscores_array = (int *)calloc(5, sizeof (int)); //creates 5 term array initiliased to 0
    }
}

void Menu::change_screen() //moves changes menu screen to screen of cursor position
{
    switch(_cursor_pos) { //uses cursor position to change screen variable to 
        case 0: //if cursor is in position 0 (top)
            _screen = START;  //sets screen to START
            break;
        case 1: //if cursor is in position 1 (middle)
            _screen = HIGHSCORES; //sets screen to HIGHSCORES
            break;
        case 2: //if cursor is in position 2 (bottom)
            _screen = SETTINGS; //sets screen to SETTINGS
            break;
    }
}

void Menu::drawSettings(N5110 &lcd) 
{
    lcd.printString("LCD Contrast",0,0);
    lcd.printString("LCD Brightness",0,2);
    lcd.printString("Frame Rate",0,4);
    switch(_cursor_pos) { //modifies current setting depending on cursor position and potentiometer
        case 0:
            _contrast = (_pot*4.0f/10.0f)+0.4f; //scale from 0-1 to 0.4-0.8 (below 0.4 no colour, above 0.8 no change)
            lcd.setContrast(_contrast); //0.54 best to see pov of ball clearly
            drawSettingsBars(lcd); //draws settings bars and prints values alongside
            break;
        case 1:
            _brightness = _pot;
            lcd.setBrightness(_brightness); //100% brightness and high contrast makes seeing ball easier 
            drawSettingsBars(lcd); //draws settings bars and prints values alongside
            break;
        case 2: 
            _frame_rate = (_pot*30.0f)+20.0f; //scales 0-1 pot value to 5-50 fps
            drawSettingsBars(lcd); //draws settings bars and prints values alongside
            break;
    }
}

void Menu::drawSettingsBars(N5110 &lcd) {
    
    lcd.drawRect(8,9,40,6,FILL_TRANSPARENT); //contrast bar
    lcd.drawRect(8,25,40,6,FILL_TRANSPARENT); //brightness bar
    lcd.drawRect(8,41,40,6,FILL_TRANSPARENT); //frame rate bar
    lcd.drawRect(8,9,40*(_contrast-0.4f)*(10.0f/4.0f),6,FILL_BLACK);
    lcd.drawRect(8,25,40*_brightness,6,FILL_BLACK); 
    lcd.drawRect(8,41,40*(_frame_rate-20.0f)/30.0f,6,FILL_BLACK); 
    char buffer[14];
    sprintf(buffer,"%.2f%",_contrast); //print contrast value to 2dp
    lcd.printString(buffer,52,1);   
    sprintf(buffer,"%.2f%",_brightness); //print brightness value to 2dp
    lcd.printString(buffer,52,3);
    sprintf(buffer,"%ifps",_frame_rate); //prints integer value of frame rate
    lcd.printString(buffer,52,5);  
}

void Menu::move_cursor(N5110 &lcd) //draws cursor in current position and moves to next position dependent on joystick direction
{
    switch(_cursor_pos) {
        case 0: //cursor on position 0
            drawCursor(lcd); //draws cursor in position
            cursor_pos_0(); //moves cursor dependent on current position and direction of joystick
            break;
        case 1: //cursor on position 1
            drawCursor(lcd);
            cursor_pos_1(); //moves cursor dependent on current position and direction of joystick
            break;
        case 2: //cursor on position 2
            drawCursor(lcd);
            cursor_pos_2(); //moves cursor dependent on current position and direction of joystick
            break;
    } 
}

void Menu::cursor_pos_0() //cursor movement from position 0
{
    switch(_joy_direction) {
        case 0: //joystick centered
            _cursor_pos = 0; //set cursor position to 0
            break;
        case 1: //joystick up
            _cursor_pos = 2; //set cursor position to 2
             break;
        case 5: //joystick down
            _cursor_pos = 1; //set cursor position to 1
            break;
    }
}

void Menu::cursor_pos_1() //cursor movement from position 1
{
    switch(_joy_direction) {
        case 0: //joystick centered
            _cursor_pos = 1; //set cursor position to 1
            break;
        case 1: //joystick up
            _cursor_pos = 0; //set cursor position to 0
            break;
        case 5: //joystick down
            _cursor_pos = 2; //set cursor position to 2
            break;
    }    
}

void Menu::cursor_pos_2() //cursor movement from position 2
{
    switch(_joy_direction) {
        case 0: //joystick centered
            _cursor_pos = 2; //set cursor position to 2
            break;
        case 1: //joystick up
            _cursor_pos = 1; //set cursor position to 1
            break;
        case 5: //joystick down
            _cursor_pos = 0; //set cursor position to 0
            break;
    }
}

void Menu::drawCursor(N5110 &lcd)
{
    switch(_cursor_pos) {
        case 0: //cursor on position 0
            lcd.drawRect(0,9,6,6,FILL_TRANSPARENT);  //draw cursor in position 0
            break;
        case 1: //cursor on position 1
            lcd.drawRect(0,25,6,6,FILL_TRANSPARENT); //draw cursor in position 1
            break;
        case 2: //cursor on position 2
            lcd.drawRect(0,41,6,6,FILL_TRANSPARENT); //draw cursor in position 2
            break; 
    }
}