Initial publish

Dependencies:   mbed

Fork of el17dg by Dmitrijs Griskovs

game/game.cpp

Committer:
Noximilien
Date:
2019-04-10
Revision:
28:35af3843de8f
Parent:
27:f05f4e738ba9
Child:
29:579e00b7f118

File content as of revision 28:35af3843de8f:

#include "mbed.h"
#include "N5110.h"
#include "Gamepad.h"

#include "models.h"
#include "main.h"
#include "game.h"
#include "geometry.h"
#include "gameobject.h"

#include "enemies.h"
#include "constants.h"
#include "stars.h"
#include "player.h"
#include "hud.h"

bool game_over = true;
int game_score;
int high_score = 0;
int score_count_for_difficulty;
int player_lifes = 3;
bool red_led_state;
int red_led_flashing;
int enemy_ship_delay_counter;

const int increase_difficulty = 50;
int enemy_ship_delay_max = 40;

Enemies enemies;
Stars stars;
Player playerShip;
GameObject gameOverLogo;
GameObject youDied;
Hud hud;

/**@brief
  * This function checks whether the requirments for the collision of the two objects,
  * are met. When those requirments are met the collision of two objects function will
  * be checking wheter the boundaries of the objects colide. If they do, the blast
  * becomes inactive, in game score increases and enemy dies.
  */
void Game::collideEnemiesAndBlasts() {
    for (int i = 0; i < max_enemies; ++i) {
        for (int j = 0; j < max_player_blasts; ++j) {
            Enemy& enemy = enemies.enemies[i];
            GameObject& blast = blasts[j];
            if (enemy.active && !enemy.dead && blast.active) {
                bool collision = circleCollideTwoObjects(
                    enemy.pos, enemies.enemy_bounds, 
                    blast.pos, blast_bounds
                );
                if (collision) {
                    enemy.die();
                    game_score += 30;
                    score_count_for_difficulty +=30;
                    blast.active = false;
                }
            }
        }
    }
}

/**@brief
  * This code does the same work as the one before but with two other objects.
  * It checks whether the requirments for the collision of the two objects,
  * are met. When those requirments are met the collision of two objects function will
  * be checking wheter the boundaries of the objects colide. If they do, the blast
  * becomes inactive, in game score increases and enemy dies.
  */
void Game::collideEnemiesBlastsAndPlayer() {
    for (int i = 0; i < max_enemies; ++i) {
        GameObject& blast = enemies.enemy_blasts[i];
        if (blast.active) {
            bool collision = circleCollideTwoObjects(
                player.pos, player_bounds,
                blast.pos, enemies.enemy_blast_bounds
            );
            if (collision) {
                gamepad.tone(87,0.3);
                gamepad.tone(287,0.2);
                gamepad.tone(423,0.4);
                printf("lost a life. left: %i \n", player_lifes);
                player_lifes -= 1;
                blast.active = false;
            }
        }
    } 
}

/**@brief
  * This code does the same work as the one before but with two other object.
  * of enemy ship and the player's ship
  */
void Game::collideEnemiesAndPlayer() {
    for (int i = 0; i < max_enemies; ++i) {
        Enemy& enemy = enemies.enemies[i];
        if (enemy.active && !enemy.dead) {
            bool collision = circleCollideTwoObjects(
                player.pos, player_bounds,
                enemy.pos, enemies.enemy_bounds
            );
            if (collision) {
                player_lifes -= 1;
                enemy.die();
            }
        }
    } 
}

/**@brief
    * This function resets all the values to their intial states when the game is
    * first began when the player dies and wants to restart the game.
    * It does not reset the values when the game is paused.
    */
void Game::startNewGame() {
    gameOverLogo.pos.x = game_area_x - 29; // 0 - the sprite length
    gameOverLogo.pos.y = game_area_y;
    youDied.pos.x = game_area_width; 
    youDied.pos.y = game_area_y;
    game_over = false;
    player.pos.x = 0; //player was defined in player.h
    player.pos.y = 24;
    stars_delay = 0;
    enemy_ship_delay_max = 40;
    enemy_ship_delay_counter = enemy_ship_delay_max;
    game_score = 0;
    score_count_for_difficulty = 0;
    player_lifes = 3;
    red_led_state = false;
    red_led_flashing = 0;
    enemy_blast_speed = 3;
    enemy_speed = 1;   
    for (int i = 0; i < max_enemies; ++i) {
        enemies.enemies[i].active = false;
    }
    for (int i = 0; i < max_player_blasts; ++i) {
        blasts[i].active = false;
    }
    for (int i = 0; i < max_enemy_blasts; ++i) {
        enemies.enemy_blasts[i].active = false;
    }
        //Reset start button event
    gamepad.check_event(gamepad.START_PRESSED);

}

/**@brief
    * A game over function that shows the sprites of "game over" and "you died".
    * Allows to reset the game to play again.
    */
void Game::gameOver() {
    drawGameOver();   
    char buffer[32];
    sprintf(buffer,"Your Score %i",game_score);
    lcd.printString(buffer,0,3);   
    wait(1);
    lcd.printString("Press Y",0,4);
    lcd.printString("to restart",0,5);
    lcd.refresh();
    bool led_state = false;
    while (!gamepad.check_event(gamepad.Y_PRESSED)){//////////////////////////////
        gamepad.led(1,(float)led_state);
        gamepad.led(2,(float)!led_state);
        gamepad.led(3,(float)led_state);
        gamepad.led(4,(float)!led_state);
        gamepad.led(5,(float)led_state);
        gamepad.led(6,(float)!led_state);
        wait(0.5);
        led_state = !led_state;
    }
}

/**@brief
    * A function tbat delays enemy spawn on low game score.
    * It decreases the enemy spawn delay as in game score increases.
    */
void Game::increaseGameDifficultyAndEnemySpawnDelay(){
    if  (enemy_ship_delay_counter <= 0){ 
        enemies.spawnNewEnemy();
        enemy_ship_delay_counter = enemy_ship_delay_max;
    }
    else { enemy_ship_delay_counter -= 1;}
    
    if (enemy_ship_delay_max >= 4 && score_count_for_difficulty >= increase_difficulty){
        enemy_ship_delay_max -= 3;
        
        if (enemy_ship_delay_max <= 20 && enemy_ship_delay_max >= 15){
            enemy_blast_speed += 1;
            enemy_speed += 1;   
        }
        score_count_for_difficulty = 0;   
    }
}

/**@brief
    * This is the main function of game.cpp, where the actual gameplay happens.
    * Here all other functions are activeated, and when the player dies, it
    * returns back to main menu "main.cpp". 
    */
bool Game::updateAndDraw() {
    //printf("update \n");
    if (game_over) {
        printf("start game \n");
        startNewGame();
    }
    
    if (gamepad.check_event(gamepad.X_PRESSED)){
        // Checking the button second time to prevent double blast.
        gamepad.check_event(gamepad.X_PRESSED); 
        playerShip.fireNewBlast();
        gamepad.tone(200,0.1);
    }
    
    playerShip.playerShipMovement();
    stars.starsSpawnDelay();
    increaseGameDifficultyAndEnemySpawnDelay();
    hud.displayLifes();
    playerShip.updateAndDrawBlasts();
    stars.updateAndDrawSmallStars();
    stars.updateAndDrawMediumStars();
    enemies.updateAndDrawEnemies();
    collideEnemiesAndBlasts();
    collideEnemiesBlastsAndPlayer();
    collideEnemiesAndPlayer();
    enemies.updateAndDrawEnemyBlasts();
    hud.drawScore();
    
    /**@brief
        * This small statment checks whether the pause button was pressed or not.
        * If it was pressed, then the game will go back to main menu and will save 
        * the current status of the object until the game is continued.
        */
    bool want_to_pause = false;
    game_over = checkForGameOver();
    if (game_over){
        printf("game over happened\n");
        gameOver();
        want_to_pause = true;
    }
    if (gamepad.check_event(gamepad.START_PRESSED)){
        printf("pausing the game\n");
        gamepad.check_event(gamepad.START_PRESSED);
        want_to_pause = true;
    }
    return want_to_pause;
}
/**@brief
    * This is a single line function to set the player lifes to 0 when the.
    * game is over. 
    */
bool Game::checkForGameOver() {
    return player_lifes == 0;
}
void Game::drawGameOver(){
    for (int i = 0; i < 42; i++){
        lcd.clear();
        lcd.drawSprite(gameOverLogo.pos.x + i, gameOverLogo.pos.y, 14, 29, (int*)gameOverSprite);
        lcd.drawSprite(youDied.pos.x - i, youDied.pos.y, 14, 24, (int*)youDiedSprite);
        lcd.refresh();
        wait(0.1);
    } 
}