Kaif Kutchwala 201267448 ELEC2645 Project

Dependencies:   mbed

Game/Game.cpp

Committer:
KaifK
Date:
2020-05-24
Revision:
20:c697902b844f
Parent:
17:2fbe40177b9c
Child:
21:d5b1160f349f

File content as of revision 20:c697902b844f:

#include "Game.h"
Ticker ticker;

volatile int sound_timer_flag = 0;
volatile int sound_sample = 0;

void timer_isr();

Game::Game(N5110 &lcd, Gamepad &pad, Ball &ball) {
    _lcd = &lcd;
    _pad = &pad;
    _ball = &ball;
}
Game::~Game() {}

void Game::init() {
    _is_goal = false;
    _lives = 3;
    _new_lives_threshold = 0;
    _level = 1;
    _score = 0;
    _highscore = 0;
    _speed = 0.30f;
    _new_speed_threshold = 0.00f;
    _x_val = 42.00f;
    _y_val = 0.00f;
    _shot_x = 0;
    _shot_y = 0;
}
void Game::play() {
    // if all live are lost game ends
    while(_lives > 0) {      
        updateSpeed();
        updateLives();    
        updateLevel();
        readInput();
        if(_is_goal) {
            _score++;
        }
        else { 
            // ball should not go through obstacle hence y value limited to 21
            // this is done after calculations to ensure accurate results
            if(_shot_y >= 9) { _shot_y = 21; }
            if(_shot_y <= 5) {_shot_y = 3; }
            _lives--; 
        }
        _ball->playShot(_shot_x, _shot_y);
        print_goal_message((int)_is_goal);
        playGoalSound((int)_is_goal + 1);
    }
    if(_score > _highscore) { set_highscore(_score);}
    _pad->leds(0.0); //turn of all leds 
}

void Game::readInput() {
    _pad->reset_buttons(); //forced debounce/reset
    _x_val = 42; //reset x_val
    _y_val = 0; //reset y_val
    while(!_pad->A_pressed()) {
        pointer_input();
    }
    _pad->reset_buttons(); //forced debounce/reset
    while(!_pad->B_pressed()) {
        power_meter_input();
    }
    convert_to_shot_x();
    convert_to_shot_y();
    _is_goal = _ball->isGoal(_level, _shot_x, _shot_y);
    //printf("x val = %.2f \n",_x_val);
    //printf("shot_x val = %d \n",_shot_x);
    //printf("y val = %.2f \n",_y_val);
    //printf("shot_y val = %d \n",_shot_y);
}
void Game::updateLives() {
    int val [6] = {0,0,0,0,0,0}; 
    // +1 life if score hits a multiple of 5 provided less than 3 lives left
    //update threshold so lives don't  increase if score stays same
    if(_score % 5 == 0 && _score != _new_lives_threshold && _lives != 3) { 
        _lives++; 
        _new_lives_threshold = _score;
    }
    //printf("Lives = %d \n", _lives);
    switch(_lives){
        case 0:
            break;
        case 1: //red leds only
            val[0] = val[3] = 1;
            break; 
        case 2: //red and yellow leds
            val[0] = val[1] = val[3] = val[4] = 1;
            break; 
        case 3: //all leds on
            for (int i = 0; i < 6; i++) {val[i] = 1;}
            break; 
        default:
            error("Invalid Number of Lives");  
            break; 
    }
    updateLeds(val);
}
void Game::updateScore() {
    char buffer[12];
    sprintf(buffer,"%d",_score);
    _lcd->printString(buffer,2,5);
}
void Game::updateSpeed() {
    if(abs(_speed) <= 3) { // max speed = 3
        if(_score % 3 == 0 && _score != _new_speed_threshold) {
            _speed = abs(_speed) + 0.20f;
            //update threshold so speed does not increase if score stays same
            _new_speed_threshold = _score;        
        }
    }
    //printf("speed = %.2f \n", _speed);
    //printf("score = %d \n", _score);
}
void Game::updateLevel() {
    _level = random_level_gen(10); //generate random level
    _ball->set_level(_level); //set level
    //printf("Level (in game) = %d \n", _level); 
}
void Game::updateLeds( int val[6]) {
    _pad->led(1,val[0]);
    _pad->led(2,val[1]); 
    _pad->led(3,val[2]); 
    _pad->led(4,val[3]); 
    _pad->led(5,val[4]); 
    _pad->led(6,val[5]);    
}
void Game::playGoalSound(int sound) {
    sound_sample = 0;
    float val = 0.0f;
    int NUM_ELEMENTS = 0;
    ticker.attach(&timer_isr,226e-7);
    if(sound == 1) {NUM_ELEMENTS = NUM_ELEMENTS_1;}
    else if(sound == 2) {NUM_ELEMENTS = NUM_ELEMENTS_3;}
    else if(sound == 3) {NUM_ELEMENTS = NUM_ELEMENTS_2;}
    while(sound_sample <= NUM_ELEMENTS) {
        if (sound_timer_flag == 1) {
            sound_timer_flag = 0;
            // convert from 0 to 255 to 0.0 to 1.0
            if(sound == 1) {val = float(miss[sound_sample])/ 256.0f;}
            else if(sound == 2) {val = float(goall[sound_sample])/ 256.0f;}
            else if(sound == 3) {val = float(over[sound_sample])/ 256.0f;}      
            // write to DAC
            _pad->write_dac(val);
            // move onto next sample
            sound_sample++;
        }
    }
}
void Game::set_highscore (int score) {
    _highscore = score;   
}
int Game::get_highscore() {
    int val = _highscore;
    return val;   
}
void Game::pointer_input() {
    updateScore();
    _ball->displayBackground();
    _ball->init();
    //draw aim pointer
    _lcd->drawLine(WIDTH / 2 - 5, 41, _x_val, HEIGHT / 2 + 7, 1);//left side
    _lcd->drawLine(WIDTH / 2 + 5, 41, _x_val, HEIGHT / 2 + 7, 1);//right side
    _lcd->drawLine(WIDTH / 2 + 5, 41, WIDTH / 2 - 5, 41, 1); //base
    _x_val += _speed;
    //printf("dir = %d \n", _speed);
    if((int)_x_val >= 70) { _speed = (-1 * _speed); }
    //pointer points out of screen i.e. 70=84 therefore, switch direction 
    //value found through trial and error using print statement
    else if((int)_x_val <= 12) { _speed = abs(_speed); }
    _lcd->refresh();
    _lcd->clear();
    wait(0.01);
}
void Game::power_meter_input() {
    updateScore();
    _ball->displayBackground();
    _ball->init();
    //keep direction of pointer
    _lcd->drawLine(WIDTH / 2 - 5, 41, _x_val, HEIGHT / 2 + 7, 1);
    _lcd->drawLine(WIDTH / 2 + 5, 41, _x_val, HEIGHT / 2 + 7, 1);
    _lcd->drawLine(WIDTH / 2 + 5, 41, WIDTH / 2 - 5, 41, 1);
    //fill and empty power meter
    _lcd->drawRect(77,27,6,_y_val,FILL_BLACK);
    _y_val += _speed/2;
    if((int)_y_val >= 20) { _speed = (-1 * _speed); } //power meter full
    else if((int)_y_val <= 0) { _speed = abs(_speed); } // power meter empty
    _lcd->refresh();
    _lcd->clear();
    wait(0.01);
}
void Game::convert_to_shot_x() {
    //convert from range 12-70 (range of pointer) to 0-84 (range of screen)
    _shot_x = ((((int)_x_val - 12) * (84)) / (70 - 12));
    //ball misses goal completely
    if(_shot_x <=7) { _shot_x = 0;}
    else if(_shot_x >=77) { _shot_x = 84;}
}
void Game::convert_to_shot_y() {
    _shot_y = ((((int)_y_val) * (24)) / (20));
    if (_shot_y >= 19) {_shot_y = 19; }//shot is low, but must enter goal
}
int Game::random_level_gen(int limit) {
    int number = (rand() % limit) + 1; //random level between 1-10
    return number;
}
void Game::print_goal_message(int n) {
    _ball->displayBackground();
    _lcd->drawRect(0,14,84,11,FILL_WHITE);//white background
    _lcd->drawRect(0,14,84,11,FILL_TRANSPARENT);//black outline
    
    switch(n) {
        case 0:
            _lcd->printString("MISS!",30,2);
            break;
        case 1:
            _lcd->printString("GOAL!",30,2);
            break;
    }    
    _lcd->refresh();
    wait(1.5);        
}
void timer_isr() {
    sound_timer_flag = 1; // set flag in the isr   
}