Initial publish

Dependencies:   mbed

Fork of el17dg by Dmitrijs Griskovs

game/boss.h

Committer:
Noximilien
Date:
2019-05-07
Revision:
40:e3bbda7444fa
Parent:
39:ca77a6d574e6

File content as of revision 40:e3bbda7444fa:

#ifndef BOSS_H
#define BOSS_H

#include "constants.h"

/** 
* Boss Class
* @brief A class to describe the states of the boss ship.
* @author Dmitrijs Griskovs
* @date 30/04/2019
*/
class Boss : public GameObject {
public:
    /**
     * @brief Maximum boss blasts on the screen.
     */
    static const int max_boss_blasts = 5; 


    GameObject boss_blasts[max_boss_blasts];
    CircleBounds boss_bounds;
    CircleBounds boss_blast_bounds;
    
    /** 
     * Constructor 
     * Sets values for the boss' sprite body circle area, the blast circle 
     * area and the circle radius for collsion callculations. Also, resets the
     * cutscene.
     */ 
    Boss() {
        boss_bounds.center.x = 5;
        boss_bounds.center.y = 8;
        boss_bounds.radius = 10;
        
        boss_blast_bounds.center.x = 1;
        boss_blast_bounds.center.y = 0;
        boss_blast_bounds.radius = 1;
        
        switch_boss_y_dir = true;
        animation_counter = 0;
        resetCutscene();  
    }
    
    /** 
     * @brief Updates and draws the boss blasts accross the screen.
     */
     void updateAndDrawBossBlasts() {
        for (int i = 0; i < max_boss_blasts; ++i) {
            if (boss_blasts[i].active) {
                boss_blasts[i].pos.x -= boss_blast_speed;
                if (boss_blasts[i].pos.x <= 0){
                    boss_blasts[i].active = false;
                    continue;
                }
                drawSprite(boss_blasts[i].pos, blast_sprite);
            }
        }
    }
    /** 
     * @brief Updates and draws the boss.
     * @details this function is monitored in game.cpp and when the boss becomes
     * inactive, the gameplay would switch from boss to normal.
     * @returns bool active, when the boss is out of lives
     */
    bool updateAndDrawBoss(){
        if(switch_boss_y_dir) { pos.y += 1;}
        else                  { pos.y -= 1;}
        if (pos.y >= (game_area_height - enemy1_height)){ switch_boss_y_dir = false;}
        else if (pos.y <= game_area_y)                  { switch_boss_y_dir = true;}
        blast_countdown -= 1;
        if (blast_countdown <= 0) {
            fireNewBlast(pos.x, pos.y + 2);
            fireNewBlast(pos.x, pos.y + enemy1_height - 2);
            blast_countdown = 10;
        }
        if(!dead() && active){ draw();}
        else{
            GameGlobals::game_score += 300;
            GameGlobals::score_count_for_boss_mode = 0;
            updateAndDrawDeathExplosion();
            lcd.normalMode();
        }
        return active;
    }
    /** 
     * @brief Updates and draws the boss' cutscene of entering the game.
     * @details It freezes the screen until the boss is set on the screen. Also,
     * it sets its position and number of lives.
     * @returns bool active, when the boss is out of lives
     */
    void updateCutscene() {
        if (!started_cutscene) {
            started_cutscene = true;
            pos.y = screen_height/2 - (enemy1_height/2);
            pos.x = screen_width;
            animation_counter = 0;
            active = true;
            boss_lives = 10;
            dead_counter = 5;
            DG_PRINTF("boss lives set to: %i \n", boss_lives);
            return;
        }
        if (animation_counter < animation_length) {
            pos.x -= 1;
            animation_counter++;
        }    
    }
    
    /** @brief draws boss' sprite.*/
    void draw() {  drawSpriteOnTop(pos, enemy1_sprite);}
    /** @brief resets the boss' cutscene.*/
    void resetCutscene() { started_cutscene = false; }
    /** 
     * @returns bool true 
     * @brief It starts the boss fight sequence when the cutscene is finished.
     */
    bool isFinishedCutscene() { return animation_counter >= animation_length; }
    /**
     * @var int boss_lives 
     * @brief contains boss' lives.
     */
    int boss_lives;
    
private:
    void updateAndDrawDeathExplosion() {
        for(int dead_counter; dead_counter >= 0; dead_counter--){
            if (dead_counter > 0) {
                if (dead_counter == 4){    
                    drawSpriteOnTop(pos, enemy1_quarter_exploded_sprite);
                } else if (dead_counter == 3){
                    drawSpriteOnTop(pos, enemy1_half_exploded_sprite);
                } else if (dead_counter == 2){
                    drawSpriteOnTop(pos, enemy1_second_quarter_exploded_sprite);
                } else if (dead_counter == 1){
                    drawSpriteOnTop(pos, enemy1_fully_exploded_sprite);
                }
            } else {
                active = false;
                DG_PRINTF("boss died \n");
            }
        }
    } 

    /** 
     * @brief Spawns a blast at the position of the boss.
     * @param x (int x) to give x position of the boss blast.
     * @param y (int y) to give y position of the boss blast.
     * @details For this function the parameters are required to be able to spawn
     * two independed from each other blasts at the same time and different
     * positions.
     */
    bool fireNewBlast(int x, int y) {
        // Search the array of blasts if inactive we can use it.
        int found = -1;
        for (int i = 0; i < max_boss_blasts; ++i) {
            if (!boss_blasts[i].active) {
                found = i;
                break;
            }
        }   
        if (found != -1) {
            boss_blasts[found].active = true;
            boss_blasts[found].pos.x = x;
            boss_blasts[found].pos.y = y;
            gamepad.tone(500,0.1);
            return true;
        }
        return false;
    }
    static const int boss_y_speed = 2;
    static const int boss_blast_speed = 4;
    static const int animation_length = 20;
    bool dead(){return boss_lives == 0;}
    bool started_cutscene;
    bool switch_boss_y_dir;
    int blast_countdown;
    int animation_counter;
    int dead_counter;
};

#endif