ELEC2645 (2018/19) / Mbed 2 deprecated el17dg

Dependencies:   mbed

Fork of el17dg by Dmitrijs Griskovs

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers game.cpp Source File

game.cpp

00001 #include "mbed.h"
00002 #include "N5110.h"
00003 #include "Gamepad.h"
00004 #include "collision_lib.h"
00005 
00006 #include "models.h"
00007 #include "main.h"
00008 #include "game.h"
00009 #include "gameobject.h"
00010 
00011 #include "boss.h"
00012 #include "enemies.h"
00013 #include "constants.h"
00014 #include "stars.h"
00015 #include "player.h"
00016 #include "hud.h"
00017 #include "gameovermanager.h"
00018 
00019 
00020 const int increase_difficulty = 70;
00021 int GameGlobals::game_score = 0;
00022 int GameGlobals::score_count_for_difficulty = 0;
00023 int GameGlobals::player_lifes = 3;
00024 int GameGlobals::high_score = 0;
00025 bool GameGlobals::is_shield_on = false;
00026 int GameGlobals::score_count_for_boss_mode = 0;
00027 
00028 Boss boss;
00029 Enemies enemies;
00030 Enemy enemy;
00031 Stars stars;
00032 Player player;
00033 GameOverManager gameOverManager;
00034 
00035 Hud hud;
00036 
00037 
00038 void Game::updateAndDrawGameplay() {
00039     checkButtonToShoot();
00040     player.updateAndDraw();
00041     player.updateAndDrawBlasts();
00042     stars.updateAndDrawSmallStars();
00043     stars.updateAndDrawMediumStars();
00044     stars.starsSpawnDelay();
00045     increaseGameDifficultyAndEnemySpawnDelay();
00046     hud.displayLifes();
00047     hud.drawScore();
00048     collideEnemiesAndBlasts();
00049     collideEnemiesBlastsAndPlayer();
00050     collideEnemiesAndPlayer();
00051     enemies.updateAndDrawEnemies();
00052     enemies.updateAndDrawEnemyBlasts();
00053     boss.updateAndDrawBossBlasts();
00054     
00055     if (checkForGameOver()) { game_state = GameState_gameover;}
00056     if (is_boss_active) { game_state = GameState_boss_cutscene;}
00057 }
00058 
00059 void Game::updateAndDrawGameover() {
00060     gameOverManager.updateAndDraw();
00061     lcd.normalMode();
00062     if (gamepad.check_event(gamepad.Y_PRESSED) && !gameOverManager.isPlayingAnimation()) {
00063         gameOverManager.reset();
00064         game_state = GameState_newgame;
00065     }
00066 }
00067 
00068 void Game::updateAndDrawBossCutscene() {
00069     boss.updateCutscene();
00070     enemies.updateAndDrawEnemyBlasts();
00071     boss.draw();
00072     player.draw();
00073     stars.updateAndDrawSmallStars();
00074     stars.updateAndDrawMediumStars();
00075     gamepad.tone(60,2);
00076     for (int i = 0; i < enemies.max_enemies; ++i) {
00077         enemies.enemies[i].active = false;
00078     }
00079     for (int i = 0; i < enemies.max_enemy_blasts; ++i) {
00080         enemies.enemy_blasts[i].active = false;
00081     }
00082     if (boss.isFinishedCutscene()) {
00083         game_state = GameState_boss_gameplay;
00084         boss.resetCutscene(); 
00085     }
00086 }
00087 
00088 void Game::updateAndDrawBossGameplay() {
00089     checkButtonToShoot();
00090     enemies.updateAndDrawEnemyBlasts();
00091     player.updateAndDraw();
00092     player.updateAndDrawBlasts();
00093     stars.updateAndDrawSmallStars();
00094     stars.starsSpawnDelay();
00095     hud.displayLifes();
00096     hud.drawScore();
00097     boss.updateAndDrawBossBlasts();
00098     collideBossAndPlayerBlasts();
00099     collideBossBlastsAndPlayer();
00100     is_boss_active = boss.updateAndDrawBoss();
00101     if (checkForGameOver()) { game_state = GameState_gameover;}
00102     if (!is_boss_active) { game_state = GameState_gameplay;}
00103 }
00104 
00105 /**
00106   * This is the main function of game.cpp, where the actual gameplay happens.
00107   * Here all other functions are activeated, and when the player dies, it
00108   * returns back to main menu "main.cpp". 
00109   */
00110 bool Game::updateAndDraw() {
00111     if (game_state == GameState_newgame) {
00112         DG_PRINTF("start game \n");
00113         startNewGame();
00114     }
00115     if (game_state == GameState_gameplay) { updateAndDrawGameplay(); }
00116     else if (game_state == GameState_boss_cutscene) { updateAndDrawBossCutscene(); }
00117     else if (game_state == GameState_boss_gameplay) { updateAndDrawBossGameplay(); }
00118     else if (game_state == GameState_gameover) { updateAndDrawGameover(); }
00119     
00120     return checkIfNeedsToReturnToMenu();
00121 }
00122 
00123 void Game::checkButtonToShoot(){
00124     if (gamepad.check_event(gamepad.X_PRESSED) && !GameGlobals::is_shield_on){
00125         // Checking the button second time to prevent double blast.
00126         gamepad.check_event(gamepad.X_PRESSED); 
00127         player.fireNewBlast();
00128         gamepad.tone(200,0.1);
00129     }
00130 }
00131 
00132 /**
00133   * This function checks whether the requirments for the collision of the two objects,
00134   * are met. When those requirments are met the collision of two objects function will
00135   * be checking wheter the boundaries of the objects colide. If they do, the blast
00136   * becomes inactive, in game score increases and enemy dies.
00137   */
00138 void Game::collideEnemiesAndBlasts() {
00139     for (int i = 0; i < enemies.max_enemies; ++i) {
00140         for (int j = 0; j < player.max_player_blasts; ++j) {
00141             Enemy& enemy = enemies.enemies[i];
00142             GameObject& blast = player.blasts[j];
00143             if (enemy.active && !enemy.dead && blast.active) {
00144                 bool collision = circleCollideTwoObjects(
00145                     enemy.pos, enemies.enemy_bounds, 
00146                     blast.pos, player.blast_bounds
00147                 );
00148                 if (collision) {
00149                     enemy.die();
00150                     DG_PRINTF("enemy got hit and dies \n");
00151                     GameGlobals::game_score += 30;
00152                     GameGlobals::score_count_for_difficulty +=30;
00153                     GameGlobals::score_count_for_boss_mode += 30;
00154                     blast.active = false;
00155                 }
00156             }
00157         }
00158     }
00159 }
00160 
00161 /**
00162   * This code does the same work as the one before but with two other objects.
00163   * It checks whether the requirments for the collision of the two objects,
00164   * are met. When those requirments are met the collision of two objects function will
00165   * be checking wheter the boundaries of the objects colide. If they do, the blast
00166   * becomes inactive, in game score increases and enemy dies.
00167   */
00168 void Game::collideEnemiesBlastsAndPlayer() {
00169     for (int i = 0; i < enemies.max_enemies; ++i) {
00170         GameObject& blast = enemies.enemy_blasts[i];
00171         if (blast.active) {
00172             bool collision = circleCollideTwoObjects(
00173                 player.pos, player.player_bounds,
00174                 blast.pos, enemies.enemy_blast_bounds
00175             );
00176             if (collision) {
00177                 if (!GameGlobals::is_shield_on){
00178                     gamepad.tone(423,0.4); 
00179                     GameGlobals::player_lifes -= 1;
00180                     DG_PRINTF("lost a life from blast. left: %i \n", GameGlobals::player_lifes);
00181                     blast.active = false;
00182                 }else{
00183                     blast.active = false;
00184                     gamepad.tone(700,0.6);
00185                 }
00186             }
00187         }
00188     } 
00189 }
00190 
00191 /**
00192   * This code does the same work as the one before but with two other object.
00193   * of enemy ship and the player's ship
00194   */
00195 void Game::collideEnemiesAndPlayer() {
00196     for (int i = 0; i < enemies.max_enemies; ++i) {
00197         Enemy& enemy = enemies.enemies[i];
00198         if (enemy.active && !enemy.dead) {
00199             bool collision = circleCollideTwoObjects(
00200                 player.pos, player.player_bounds,
00201                 enemy.pos, enemies.enemy_bounds
00202             );
00203             if (collision) {
00204                 GameGlobals::player_lifes -= 1;
00205                
00206                 enemy.die();
00207                 DG_PRINTF("enemy got hit from collsion and dies");
00208                 DG_PRINTF("lost a life from enemy col. left: %i \n", GameGlobals::player_lifes);
00209             }
00210         }
00211     } 
00212 }
00213 
00214 void Game::collideBossAndPlayerBlasts() {
00215     for (int i = 0; i < player.max_player_blasts; ++i) {
00216         GameObject& blast = player.blasts[i];
00217         if (blast.active) {
00218             bool collision = circleCollideTwoObjects(
00219                 boss.pos, boss.boss_bounds,
00220                 blast.pos, player.blast_bounds
00221             );
00222             if (collision) {
00223                 boss.boss_lives -= 1;
00224                 gamepad.tone(123,0.4);
00225                 blast.active = false;
00226                 DG_PRINTF("boss has. left: %i \n", boss.boss_lives);
00227             }
00228         }
00229     } 
00230 }
00231 
00232 void Game::collideBossBlastsAndPlayer() {
00233     for (int i = 0; i < boss.max_boss_blasts; ++i) {
00234         GameObject& blast = boss.boss_blasts[i];
00235         if (blast.active) {
00236             bool collision = circleCollideTwoObjects(
00237                 player.pos, player.player_bounds,
00238                 blast.pos, boss.boss_blast_bounds
00239             );
00240             DG_PRINTF("player pos:%i,%i; offset:%i,%i; radius:%f.3; \n", player.pos.x, player.pos.y, player.player_bounds.center.x, player.player_bounds.center.y, player.player_bounds.radius);
00241             DG_PRINTF("blast pos:%i,%i; offset:%i,%i; radius:%f.3; \n", blast.pos.x, blast.pos.y, boss.boss_blast_bounds.center.x, boss.boss_blast_bounds.center.y, boss.boss_blast_bounds.radius);
00242             if (collision) {
00243                 if (!GameGlobals::is_shield_on){
00244                     
00245                     gamepad.tone(423,0.4); 
00246                     GameGlobals::player_lifes -= 1;
00247                     blast.active = false;
00248                     DG_PRINTF("collision happened;\n");
00249                     DG_PRINTF("lost a life from blast. left: %i \n", GameGlobals::player_lifes);
00250                 }else{
00251                     blast.active = false;
00252                     gamepad.tone(700,0.6);
00253                 }
00254             }
00255         }
00256     } 
00257 }
00258 
00259 /**
00260     * This function resets all the values to their intial states when the game is
00261     * first began when the player dies and wants to restart the game.
00262     * It does not reset the values when the game is paused.
00263     */
00264 void Game::startNewGame() {
00265     is_boss_active = false;
00266     game_state = GameState_gameplay;
00267     player.pos.x = 0; //player was defined in player.h
00268     player.pos.y = 24;
00269     stars.stars_delay = 0;
00270     enemy_ship_delay_max = 40;
00271     enemy_ship_delay_counter = enemy_ship_delay_max;
00272     GameGlobals::is_shield_on = false;
00273     GameGlobals::game_score = 0;
00274     GameGlobals::score_count_for_difficulty = 0;
00275     GameGlobals::player_lifes = 3;
00276     GameGlobals::score_count_for_boss_mode = 0;
00277     hud.resetRedLed();
00278     enemies.enemy_blast_speed = 3;
00279     enemy.enemy_speed = 1;
00280     gamepad.check_event(gamepad.START_PRESSED); 
00281     for (int i = 0; i < enemies.max_enemies; ++i) {
00282         enemies.enemies[i].active = false;
00283     }
00284     for (int i = 0; i < player.max_player_blasts; ++i) {
00285         player.blasts[i].active = false;
00286     }
00287     for (int i = 0; i < enemies.max_enemy_blasts; ++i) {
00288         enemies.enemy_blasts[i].active = false;
00289     }
00290      for (int i = 0; i < boss.max_boss_blasts; ++i) {
00291         boss.boss_blasts[i].active = false;
00292     }
00293     gamepad.check_event(gamepad.START_PRESSED);
00294 }
00295 
00296 /**
00297     * A function tbat delays enemy spawn on low game score.
00298     * It decreases the enemy spawn delay as in game score increases.
00299     * The enemy spawn delay is located in game.cpp because the game difficulty
00300     * depends on the on how fast enemy appears.
00301     */
00302 void Game::increaseGameDifficultyAndEnemySpawnDelay(){
00303     if  (enemy_ship_delay_counter <= 0){ 
00304         enemies.spawnNewEnemy();
00305         enemy_ship_delay_counter = enemy_ship_delay_max;
00306     }
00307     else { enemy_ship_delay_counter -= 1;}
00308     
00309     if (enemy_ship_delay_max >= 4 && GameGlobals::score_count_for_difficulty >= increase_difficulty){
00310         //decrease enemy delay spawn.
00311         enemy_ship_delay_max -= 3;
00312         if (enemy_ship_delay_max <= 20 && enemy_ship_delay_max >= 15){
00313             enemies.enemy_blast_speed += 1;
00314             enemy.enemy_speed += 1;   
00315         }
00316         GameGlobals::score_count_for_difficulty = 0;   
00317     }
00318     if (GameGlobals::score_count_for_boss_mode >= 400){
00319         is_boss_active = true; 
00320         lcd.inverseMode();
00321     }
00322 }
00323 
00324 bool Game::forceShildActivate(){
00325     if (gamepad.check_event(gamepad.R_PRESSED)){
00326        GameGlobals::is_shield_on = !GameGlobals::is_shield_on; 
00327     }   
00328     return GameGlobals::is_shield_on;
00329 }
00330 
00331 /**
00332     * This is a single line function to set the player lifes to 0 when the.
00333     * game is over. 
00334     */
00335 bool Game::checkForGameOver() {
00336     return GameGlobals::player_lifes <= 0;
00337 }
00338 
00339 /**  This small statment checks whether the pause button was pressed or not.
00340   * If it was pressed, then the game will go back to main menu and will save 
00341   * the current status of the object until the game is continued.
00342   */
00343 bool Game::checkIfNeedsToReturnToMenu(){
00344     bool want_to_pause = false;
00345 
00346     if (gamepad.check_event(gamepad.START_PRESSED)){
00347         DG_PRINTF("game paused\n");
00348         gamepad.check_event(gamepad.START_PRESSED);
00349         gamepad.check_event(gamepad.A_PRESSED);
00350         want_to_pause = true;
00351     }
00352     return want_to_pause;
00353 }