ELEC2645 (2018/19) / Mbed 2 deprecated el17aio

Dependencies:   mbed

RosenEngine/RosenEngine.cpp

Committer:
ikenna1
Date:
2019-05-09
Revision:
52:29772e31a620
Parent:
49:aa204bf7ee2e
Child:
53:3fdc4486f672

File content as of revision 52:29772e31a620:

#include "RosenEngine.h"

DigitalIn A(PTB9);

// Constructor
RosenEngine::RosenEngine()
{

}
// Destructor
RosenEngine::~RosenEngine()
{

}


void RosenEngine::init(int ship_width,int ship_height,int ship_speed,int ship_xpos,int ship_ypos)
{
    // initialise the game parameters
    _ship.init(ship_width,ship_height,ship_speed,ship_xpos,ship_ypos);
    _no_shooters = 0;
    _no_seekers = 0;
    _enemy.init(_no_shooters,_no_seekers);
    _menu.init(16);
    _health.init(_shipUsed);
    _times_run = 0;
    _score = 0;
    _dead = false;
    _intro = false;
    _wait_time = 2.25;

}
void RosenEngine::reset()
{
    // reinitialize parameters once back is pressed and game is exited
    _enemy.init(_no_shooters,_no_seekers);
    _health.init(_shipUsed);
    _wait_time = 2.25;
    _times_run = 0;
    _score = 0;
    _no_shooters = 0;
    _dead = false;
    _no_seekers = 0;
}

void RosenEngine::read_input(Gamepad &pad)
{
    // read all inputs from the gamepad
    Vector2D mapped_coord = pad.get_coord();
    _joystick.x = mapped_coord.x;
    _joystick.y = mapped_coord.y;
    _d = pad.get_direction();
    wait(0.1);
    // printf("_joystick.x ,_joystick.y = %f , %f\n",_joystick.x, _joystick.y);
}

void RosenEngine::draw(N5110 &lcd, Gamepad &pad)
{
    // Draw border
    lcd.drawRect(0,0,78,48,FILL_TRANSPARENT);
    // Draw all other game assets 
    _health.draw_health(lcd,_shipUsed);
    _health.draw_shields(lcd);
    _enemy.draw_seeker(lcd);
    _enemy.draw_shooter(lcd);
    _enemy.draw_shw(lcd,pad);
    draw_ship(lcd,pad);
    disp_points(lcd);
    // if player dies display death scene
    if(_dead == true) {
        game_over(lcd);
    }
}
void RosenEngine::draw_ship(N5110 &lcd, Gamepad &pad)
{
        // find the closest enemy (used in orions firing)
        Vector2D inde = find_closest1();
        int index = inde.x;
        Vector2D closest = find_closest2(index);
        // Draw ships and set ship parameters depending on the ship being used
        switch (_shipUsed) {
        case kestrel:
            _ship.set_parameters(9,6,4);
            _ship.draw_ship(lcd,_shipUsed);
            _weapons.draw(lcd,pad,_shipUsed,closest);
            break;
        case imperion:
            _ship.set_parameters(7,10,2);
            _ship.draw_ship(lcd,_shipUsed);
            _weapons.draw(lcd,pad,_shipUsed,closest);
            break;
        case orion:
            _ship.set_parameters(7,10,3);
            _ship.draw_ship(lcd,_shipUsed);
            _weapons.draw(lcd,pad,_shipUsed,closest);
            break;
    }
    //printf("_shipUsed = %d\n",_shipUsed);
}

void RosenEngine::update(Gamepad &pad)
{
    // set the ship in use (kestrel imperion or orion)
    set_shipUsed();
    // update enemies
    _enemy.update_seeker(_shipPos.x, _shipPos.y);
    _enemy.update_shooter(_shipPos.x, _shipPos.y);
    _enemy.update_shw();
    // update ship weapons
    update_ship_weapon(pad);
    // check collisions
    shooter_ship_collision(pad);
    seeker_ship_collision(pad);
    shooterw_ship_collision(pad);
    imperionw_seeker_collision(pad);
    kestrelw_shooter_collision(pad);
    imperionw_shooter_collision(pad);
    orionw_collision(pad);
    // check health
    check_health();
    // increase difficulty over time
    scaling(timer(12));

}
void RosenEngine::update_ship_weapon(Gamepad &pad)
{
    // update ship weapons based on ship being used
    if(_shipUsed == kestrel) {
        _ship.update_ship(_joystick.x,_joystick.y);
        _weapons.update();
        kestrelw_seeker_collision(pad);
    }
    if(_shipUsed == imperion && A == false) {
        _ship.update_ship(_joystick.x,_joystick.y);
        _weapons.update();
    }
    if(_shipUsed == orion) {
        _ship.update_ship(_joystick.x,_joystick.y);
        _weapons.update();
    }
}
void RosenEngine::get_pos()
{
    // get ship position
    _shipPos = _ship.get_pos();
    // get enemy position
    _seekerPos[0] = _enemy.get_seekerpos(1);
    _seekerPos[1] = _enemy.get_seekerpos(2);
    _seekerPos[2] = _enemy.get_seekerpos(3);
    _shooterPos[0] = _enemy.get_shooterpos(1);
    _shooterPos[1] = _enemy.get_shooterpos(2);
    _shooterPos[2] = _enemy.get_shooterpos(3);
    _shooterWPos[0] = _enemy.get_shwpos(1);
    _shooterWPos[1] = _enemy.get_shwpos(2);
    _shooterWPos[2] = _enemy.get_shwpos(3);
    // set ship size
    set_ship_size();
    // weapons are initialized here to pass accurate size values to the weapon class
    _weapons.init(_shipPos.x, _shipPos.y, _shipWidth);
    _ycursor = _menu.get_ycursor();
}
void RosenEngine::set_ship_size()
{
    // change ship size depending on ship being used
    switch (_shipUsed) {
        case kestrel:
            _shipWidth = 9;
            _shipHeight = 6;
            break;
        case imperion:
            _shipWidth = 7;
            _shipHeight = 10;
            break;
        case orion:
            _shipWidth = 7;
            _shipHeight = 10;
            break;
    }
}
void RosenEngine::title(N5110 &lcd)
{
    // display main menu screen
    _menu.title(lcd,_shipUsed);
    _menu.update(_d,_joystick);
}
int RosenEngine::get_ycursor()
{
    _ycursor = _menu.get_ycursor();
    return _ycursor;
}
void RosenEngine::set_shipUsed()
{
    // assign the ship being used based on xcursor which is the cursor in
    // the ship select part of the menu
    int shipno = _menu.get_xcursor();
    _shipUsed = (SHIP)shipno;
}
void RosenEngine::ship_select(N5110 &lcd)
{
    _menu.update(_d,_joystick);
    _menu.disp_ships(lcd);
}
bool RosenEngine::check_collision(int xpos1, int ypos1,int width1,int height1,int xpos2, int ypos2,int width2,int height2)
{
    // Create arrays of all positions with appropriate height and length
    int xpos1_array[width1];
    int ypos1_array[height1];
    int xpos2_array[width2];
    int ypos2_array[height2];
    bool xcol = false;
    bool ycol = false;
    bool col = false;
    //printf("variables declared\n");
    // Loop through both height and width to get a 2D aray of the sprites position
    // and compare all positionr returning true is any match
    for(int cx = 0; cx<width1; cx=cx+1) {
        xpos1_array[cx]= xpos1 + cx;
        for(int nx = 0; nx<width2; nx=nx+1) {
            xpos2_array[nx]= xpos2 + nx;
            if(xpos2_array[nx] == xpos1_array[cx]) {
                xcol = true;
            }
        }
    }
    //printf("first loop done\n");
    for(int cy = 0; cy<height1; cy=cy+1) {
        ypos1_array[cy]= ypos1 + cy;
        for(int ny = 0; ny<height2; ny=ny+1) {
            ypos2_array[ny]= ypos2 + ny;
            if(ypos2_array[ny] == ypos1_array[cy]) {
                ycol = true;
            }
        }
    }
    // if both the hight and width position values are equal a collision has occured
    col = (xcol & ycol);
    return col;
}
bool RosenEngine::check_collision1(int xpos1,int width1,int xpos2,int width2)
{
    // Create arrays of all positions with appropriate width values
    int xpos1_array[width1];
    int xpos2_array[width2];
    bool xcol = false;
    // loop through both arrays comparing their values and return true if any are equal
    for(int cx = 0; cx<width1; cx=cx+1) {
        xpos1_array[cx]= xpos1 + cx;
        for(int nx = 0; nx<width2; nx=nx+1) {
            xpos2_array[nx]= xpos2 + nx;
            if(xpos2_array[nx] == xpos1_array[cx]) {
                xcol = true;
            }
        }
    }
    return xcol;
}

void RosenEngine::seeker_ship_collision(Gamepad &pad)
{
    bool col1,col2,col3;
    // Check for any collisions using the check_collision function
    col1 = check_collision(_shipPos.x,_shipPos.y,9,6,_seekerPos[0].x, _seekerPos[0].y,10,7);
    col2 = check_collision(_shipPos.x,_shipPos.y,9,6,_seekerPos[1].x, _seekerPos[1].y,10,7);
    col3 = check_collision(_shipPos.x,_shipPos.y,9,6,_seekerPos[2].x, _seekerPos[2].y,10,7);
    int sel = 0;
    if (col1 == true && _no_seekers >= 1) {
        sel = 1;
    }
    if (col2 == true && _no_seekers >= 2) {
        sel = 2;
    }
    if (col3 == true && _no_seekers >= 3) {
        sel = 3;
    }
    // printf("col1 = %d, col2 = %d, col3 = %d, no_seekers = %d\n",col1,col2,col3,_no_seekers);
    // if there is a collision between any seeker and the ship update both the seeker and the ships health
    if(sel != 0) {
        _health.update(5,pad);
        _health.seekerh_update(sel,10);
        pad.tone(500,0.05);
        wait(0.05);
    }
}
void RosenEngine::shooter_ship_collision(Gamepad &pad)
{
    bool col1,col2,col3;
    int sel = 0;
    // Check for any collisions using the check_collision function
    col1 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterPos[0].x, _shooterPos[1].y,10,7);
    col2 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterPos[1].x, _shooterPos[0].y,10,7);
    col3 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterPos[2].x, _shooterPos[0].y,10,7);

    if(col1 == true && _no_shooters >= 1) {
        sel = 1;
    }
    if(col2 == true && _no_shooters >= 2) {
        sel = 2;
    }
    if(col3 == true && _no_shooters >= 3) {
        sel = 3;
    }
    // if there is a collision between any shooter and the ship update both the shooter and the ships health
    if(sel != 0) {// sel is default 0 and will only change if a collision occurs
        _health.update(1,pad);
        _health.shooterh_update(sel,10);
        pad.tone(500,0.05);
        wait(0.05);
    }
}
void RosenEngine::shooterw_ship_collision(Gamepad &pad)
{
    bool col1,col2,col3;
    int sel = 0;
    // Check for any collisions using the check_collision function
    col1 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterWPos[0].x, _shooterWPos[1].y,2,2);
    col2 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterWPos[1].x, _shooterWPos[2].y,2,2);
    col3 = check_collision(_shipPos.x,_shipPos.y,9,6,_shooterWPos[2].x, _shooterWPos[2].y,2,2);

    if(col1 == true && _no_shooters >= 1) {
        sel = 1;
    }
    if(col2 == true && _no_shooters >= 2) {
        sel = 2;
    }
    if(col3 == true && _no_shooters >= 3) {
        sel = 3;
    }
    // if there is a collision and the ship was hit update the ships damage
    if(sel != 0) {// sel is default 0 and will only change if a collision occurs
        _health.update(1,pad);
        pad.tone(500,0.05);
        wait(0.05);
    }
}
void RosenEngine::kestrelw_seeker_collision(Gamepad &pad)
{   // the kestrel fires a projectile whose x and y values must be checked with the
    // x, and y, values of every enemy to check for a collision
    bool col1, col2, col3;
    int sel = 0;
    Vector2D missle_pos = _weapons.get_pos(_shipUsed);  // get the kestrel's projectile position
    // Check for any collisions using the check_collision function
    col1 = check_collision(_seekerPos[0].x,_seekerPos[0].y,9,6,missle_pos.x,missle_pos.y,1,1);
    col2 = check_collision(_seekerPos[1].x,_seekerPos[1].y,9,6,missle_pos.x,missle_pos.y,1,1);
    col3 = check_collision(_seekerPos[2].x,_seekerPos[2].y,9,6,missle_pos.x,missle_pos.y,1,1);
    if (col1 == true && _no_seekers >= 1) {
        sel = 1;
    }
    if (col2 == true && _no_seekers >= 2) {
        sel = 2;
    }
    if (col3 == true && _no_seekers >= 3) {
        sel = 3;
    }
    // if there are collisions update the seekers health
    if(sel != 0) {// sel is default 0 and will only change if a collision occurs
        pad.tone(500,0.05);
        _health.seekerh_update(sel,5);
        wait(0.05);
    }
}
void RosenEngine::imperionw_seeker_collision(Gamepad &pad)
{   // the imperion fires a lazer to the top of screen as such we don't need to check all the
    // x, y values for the sprite to be sure of collisions just the x value. as long as the ship is above 
    // the targetted enemy a collision will register
    bool col1,col2,col3;
    int sel = 0;
    if(_shipUsed == imperion) {
        if(_shipPos.y > _seekerPos[0].y + 6) { // only regiser if seeker is above ship
            col1 = check_collision1(_seekerPos[0].x,9,_shipPos.x  + 2,3); // check for collision using the check_collision1 function
            if (col1 == true && A == true && _no_seekers >= 1) {    
                sel = 1;        // if there is a collision set an appropriate select value
            }
        }
        if(_shipPos.y > _seekerPos[1].y + 6) {
            col2 = check_collision1(_seekerPos[1].x,9,_shipPos.x  + 2,3);
            if (col2 == true && A == true && _no_seekers >= 2) {
                sel = 2;
            }
        }
        if(_shipPos.y > _seekerPos[0].y + 6) {
            col3 = check_collision1(_seekerPos[2].x,9,_shipPos.x  + 2,3);
            if (col3 == true && A == true && _no_seekers >= 3) {
                sel = 3;
            }
        }
    }
    // if a collision occured update the seekers health
    if(sel != 0) {// sel is default 0 and will only change if a collision occurs
        _health.seekerh_update(sel,10);
        pad.tone(500,0.05);
        wait(0.05);
    }
}
void RosenEngine::kestrelw_shooter_collision(Gamepad &pad)
{
    Vector2D missle_pos = _weapons.get_pos(_shipUsed); // get the kestrel's projectile position
    bool col1, col2, col3;
    int sel = 0;
    // Check for any collisions using the check_collision function
    col1 = check_collision(_shooterPos[0].x,_shooterPos[0].y,9,6,missle_pos.x,missle_pos.y,1,1);
    col2 = check_collision(_shooterPos[1].x,_shooterPos[1].y,9,6,missle_pos.x,missle_pos.y,1,1);
    col3 = check_collision(_shooterPos[2].x,_shooterPos[2].y,9,6,missle_pos.x,missle_pos.y,1,1);
    if (col1 == true && _no_shooters >= 1) {
        sel = 1;
    }
    if (col2 == true && _no_shooters >= 2) {
        sel = 2;
    }
    if (col3 == true && _no_shooters >= 3) {
        sel = 3;
    }
    // if a collision did occur update the right shooter using the select value
    if(sel != 0) {  // sel is default 0 and will only change if a collision occurs
        pad.tone(500,0.05);
        _health.shooterh_update(sel,5);
        wait(0.05);
    }
}
void RosenEngine::imperionw_shooter_collision(Gamepad &pad)
{
    bool col1,col2,col3;
    int sel = 0;
    // check collision using check_collision1 function
    if(_shipUsed == imperion) {
        if(_shipPos.y > _shooterPos[0].y + 6) {
            col1 = check_collision1(_shooterPos[0].x,9,_shipPos.x  + 2,3);
            if (col1 == true && A == true && _no_shooters >= 1) {
                sel = 1;
            }
        }
        if(_shipPos.y > _shooterPos[1].y + 6) {
            col2 = check_collision1(_shooterPos[1].x,9,_shipPos.x  + 2,3);
            if (col2 == true && A == true && _no_shooters >= 2) {
                sel = 2;
            }
        }
        if(_shipPos.y > _shooterPos[2].y + 6) {
            col3 = check_collision1(_shooterPos[2].x,9,_shipPos.x  + 2,3);
            if (col3 == true && A == true && _no_shooters >= 3) {
                sel = 3;
            }
        }
    }
    // if a collision did occur update the shooters health
    if(sel != 0) {// sel is default 0 and will only change if a collision occurs
        _health.shooterh_update(sel,10);
        pad.tone(500,0.05);
        wait(0.05);
    }
}
void RosenEngine::orionw_collision(Gamepad &pad)
{   // the orions weapon is an arc weapon that latches on to the nearest enemy.
    // as the nearest enemy position has already been found in dind_closest()
    // all we need to do now is ensure that the enemy is within range of the orions weapon
    Vector2D inde = find_closest1();
    int index1 = inde.x;
    int index2 = inde.x - 3;
    int distance = inde.y;

    // enemy 1,2 and 3 are shooters
    if(_no_shooters >= index1 && A == true && distance < 15) {// the wepon fires when a is pressed and the enemy ship is within the distaance
        _health.shooterh_update(index1,10);
        pad.tone(500,0.05);
        wait(0.05);
    }
    // enemy 4,5 and 6 are seekers so 3 is subtracted from inde.x to compensate
    if(_no_seekers >= index2 && A == true && distance < 15) {
        _health.seekerh_update(index2,10);
        pad.tone(500,0.05);
        wait(0.05);
    }


}
void RosenEngine::check_health()
{
    // check player and enemy health
    check_se_health();
    check_sh_health();
    Vector2D hp = _health.get_hp();
    if(hp.x <= 0) {
        // printf("player deaad\n");
        _dead = true;
    }

}
void RosenEngine::check_se_health()
{
    // set sel (select) as default 0
    int sel = 0;
    // get the seekers health
    int seeker1_health = _health.get_seekerh(1);
    int seeker2_health = _health.get_seekerh(2);
    int seeker3_health = _health.get_seekerh(3);
    // printf("seeker1_h = %d, seeker2_h = %d, seeker3_h = %d\n",seeker1_health,seeker2_health,seeker3_health);
    // set sel (select) depending on if any seekers health falls below zero
    if(seeker1_health == 0) {
        sel = 1;
    }
    if(seeker2_health == 0) {
        sel = 2;
    }
    if(seeker3_health == 0) {
        sel = 3;
    }
    // reset seeker and update score when seekers health goes to zero
    if(sel != 0) { 
        _enemy.reset_seeker(sel);
        _health.reset_seekerh(sel);
        _score = _score + 10;
    }
}
void RosenEngine::check_sh_health()
{   // set sel (select) as default 0
    int sel = 0;
    // get the shooters health
    int shooter1_health = _health.get_shooterh(1);
    int shooter2_health = _health.get_shooterh(2);
    int shooter3_health = _health.get_shooterh(3);
    // set sel depending on if any shooters health falls below zero
    if(shooter1_health == 0) {
        sel = 1;
    }
    if(shooter2_health == 0) {
        sel = 2;
    }
    if(shooter3_health == 0) {
        sel = 3;
    }
    // reset shooter and update score when shooter health goes to zero
    if(sel != 0) {
        _enemy.reset_shooter(sel);
        _health.reset_shooterh(sel);
        _score = _score + 20;
    }
}
int RosenEngine::rand_no()
{
    // seeds and returns a random number using the ctime library
    srand(time(NULL));
    int rand_no = (rand() %45) + 1;
    return rand_no;
}
float RosenEngine::timer(int fps)
{
    // using the amount of times run and the frames per second set the amount of
    // time past is calculated
    _times_run = _times_run + 1;
    float time_frame = 1.0f/fps;
    float time_elapsed = _times_run * time_frame;
    // printf("time elapsed = %f,time frame = %f, _times_run = %d\n",time_elapsed,time_frame,_times_run);
    return time_elapsed;
}
void RosenEngine::score(int points)
{
    _score = _score + points;
}
bool RosenEngine::dead()
{
    return _dead;
}

void RosenEngine::scaling(float time_elapsed)
{
    // increases difficulty as game progresses
    if(time_elapsed == _wait_time) { // check if time elapsed is equal to the wit time
        _no_shooters = _no_shooters + 1; // update number of shooters and seekers after wait time
        _no_seekers = _no_seekers + 1;  //increase wait time
        _enemy.sh_scaling(time_elapsed);
        _wait_time = _wait_time + 10.00;
    }
    // limit the number of seekers and number of shooters to 3
    if(_no_shooters > 3) {
        _no_shooters = 3;
    }
    if(_no_seekers > 3) {
        _no_seekers = 3;
    }
    // set approriate enemy numbers
    _enemy.set_noshooters(_no_shooters);
    _enemy.set_noseekers(_no_seekers);
    // printf("time_elapsed = %f, no_shooters = %d, wait_time = %f\n",time_elapsed,_no_shooters,_wait_time);
}
void RosenEngine::game_over(N5110 &lcd)
{
    // Display random tips after every loss
    _lore.display(lcd,rand_no());
}
void RosenEngine::intro(N5110 &lcd)
{
    // display intro
    _lore.intro(lcd);
    _intro = true;
}
void RosenEngine::disp_points(N5110 &lcd)
{
    // display players points on screen
    char buffer[10];
    sprintf(buffer,"%d",_score);
    lcd.printString(buffer,2,0);
}
Vector2D RosenEngine::get_enemynum()
{
    // return the number of enemy shooters and seekers currently on play
    return{_no_shooters,_no_seekers};
}
int RosenEngine::range(int x1, int y1, float x2, float y2)
{
    // calculates average distance between two points
    float rangex = (abs(x1 - x2));
    float rangey = (abs(y1 - y2));
    int distance = floor((rangex+rangey)/2);
    return distance;
}
Vector2D RosenEngine::find_closest1()
{
    // get the distance for all enemies
    int sh1 = range(_shipPos.x,_shipPos.y,_shooterPos[0].x,_shooterPos[0].y);
    int sh2 = range(_shipPos.x,_shipPos.y,_shooterPos[1].x,_shooterPos[1].y);
    int sh3 = range(_shipPos.x,_shipPos.y,_shooterPos[2].x,_shooterPos[2].y);
    int se1 = range(_shipPos.x,_shipPos.y,_seekerPos[0].x,_seekerPos[0].y);
    int se2 = range(_shipPos.x,_shipPos.y,_seekerPos[1].x,_seekerPos[1].y);
    int se3 = range(_shipPos.x,_shipPos.y,_seekerPos[2].x,_seekerPos[2].y);

    int close[6] = {sh1,sh2,sh3,se1,se2,se3};
    // find index of the smallest element
    int index = 0;
    int smallest = close[0];
    for(int i=0; i<6; i=i+1) {
        if(smallest>close[i]) {
            smallest=close[i];
            index = i;
        }
    }
    // return the index, so we know what the closest enemy, and the distance to check its in range
    return {(index + 1),smallest};
}
Vector2D RosenEngine::find_closest2(int index)
{
    // return the position of the closest enemy
    if(index == 1 && _no_shooters >= 1) {
        return {_shooterPos[0].x,_shooterPos[0].y};
    }
    if(index == 2 && _no_shooters >= 2) {
        return {_shooterPos[1].x,_shooterPos[1].y};
    }
    if(index == 3 && _no_shooters >= 3) {
        return {_shooterPos[2].x,_shooterPos[2].y};
    }
    if(index == 4 && _no_seekers >= 1 ) {
        return {_seekerPos[0].x,_seekerPos[0].y};
    }
    if(index == 5 && _no_seekers >= 2) {
        return {_seekerPos[1].x,_seekerPos[1].y};
    }
    if(index == 6 && _no_seekers >= 3) {
        return {_seekerPos[2].x,_seekerPos[2].y};
    }

}
Vector2D RosenEngine::get_shipPos()
{
    return{_shipPos};
}