Rebuild Back Better

Rebuild Back Better

Progress Report 1

I am happy to start working on RBB again. This time, I added the background image to the Main Menu, the Pause Menu, and the Gameplay class.

The background of the Main Menu was easily added by expanding the behavior of the Main Menu class. I also edited its constructor to load each resource using async.

MainMenu::MainMenu(    std::string &font1Path, std::string &font2Path, 
                                        std::string &sfxPath, std::string &musicPath,
                                        int width, int height, SDL_Renderer *inputRenderer,
                                        std::string bgImageLocation)
{
    // Load Main Menu elements
    renderer = inputRenderer;
    auto getTitlefont = std::async(std::launch::async, LoadFont, font1Path, 150);
    auto getMenuFont = std::async(std::launch::async, LoadFont, font2Path, 60);
    auto getImage = std::async(std::launch::async, IMG_Load, bgImageLocation.c_str());
    menuMusic = new AudioPlayer<Mix_Music>(musicPath);

    getTitlefont.wait();
    getMenuFont.wait();
    getImage.wait();
    titleFont = getTitlefont.get();
    menuFont = getMenuFont.get();
    backgroundImage = getImage.get();

    if (titleFont == nullptr || menuFont == nullptr || backgroundImage == nullptr)
    {
        std::cout << "Menu Elements have not loaded properly" << std::endl;
        std::cout << IMG_GetError() << std::endl;
        std::cout << SDL_GetError() << std::endl;
        exit(-1);
    }

    menuMusic->PlayAudio(-1, 500);
    menuTitle = LoadTextElement(titleFont, width, height, 0.245, 0.08);
    menuContinue = LoadTextElement(    menuFont, sfxPath, width, height, 0.4, 0.4);
    menuStart = LoadTextElement(    menuFont, sfxPath, width, height, 0.428, 0.5);
    menuExit = LoadTextElement(    menuFont, sfxPath, width, height, 0.436, 0.6);
    menuContinue->isEnabled = false;
    menuStart->isEnabled = true;
    menuExit->isEnabled = true;
}

void MainMenu::DisplayMainMenu(float mX, float mY, float width, float height)
{
    // Show background image
    SDL_Surface *convertSurface = SDL_ConvertSurface(backgroundImage, backgroundImage->format);

    if (convertSurface == nullptr)
    {
        std::cout << "Failed to load background image" << std::endl;
    }

    SDL_Texture *backgroundImageTexture = SDL_CreateTextureFromSurface(renderer, convertSurface);
    SDL_SetTextureColorMod(backgroundImageTexture, 125, 125, 125);
    const SDL_FRect backgroundImageHolder = {0, 0, width, height};
    SDL_RenderTexture(renderer, backgroundImageTexture, nullptr, &backgroundImageHolder);
    SDL_DestroySurface(convertSurface);
    SDL_DestroyTexture(backgroundImageTexture);

    menuTitle->CreateTextElement("Rebuild Back Better");    
    menuContinue->CreateTextElement("Continue", mX, mY);
    menuStart->CreateTextElement("Start", mX, mY);
    menuExit->CreateTextElement("Exit", mX, mY);        
}

The Pause Menu class only functions during gameplay. When the user presses the ESCAPE key, the background darkens, the game freezes, and the menu appears. Currently, the only feature that works is the background darkening when the game is paused.

#pragma once
#include <iostream>
#include <future>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <string>

struct PauseMenu
{
    static float menuBoxWidth, menuBoxHeight;
    static float menuBoxX, menuBoxY;
    static bool isPaused;
    static TTF_Font *pauseMenuFont;

    enum Selection
    {
        CONTINUE = 0,
        SAVE,
        QUITTOMAINMENU
    };

    PauseMenu(std::string pathToFont);
    ~PauseMenu();
    static TTF_Font *LoadFont(std::string urlToFont, unsigned int fontSize);
    static void DisplayPauseMenu(    float getMouseX, float getMouseY, 
                                    int windowWidth, int windowHeight, 
                                    SDL_Renderer *getRenderer);
};

#include "pausemenu.h"

TTF_Font *PauseMenu::pauseMenuFont = nullptr;
bool PauseMenu::isPaused = false;
float PauseMenu::menuBoxX = 0;
float PauseMenu::menuBoxY = 0;
float PauseMenu::menuBoxHeight = 0;
float PauseMenu::menuBoxWidth = 0;

TTF_Font *PauseMenu::LoadFont(std::string urlToFont, unsigned int fontSize)
{
    TTF_Font *font = TTF_OpenFont(urlToFont.c_str(), fontSize);
    if (font == nullptr)
    {
        std::cout << "Failed to create font ";
        std::cout << SDL_GetError() << std::endl;
        return nullptr;
    }
    return font;
}

PauseMenu::PauseMenu(std::string pathToFont)
{
    auto getFont = std::async(std::launch::async, LoadFont, pathToFont, 50);
    getFont.wait();
    pauseMenuFont = getFont.get();
}

PauseMenu::~PauseMenu()
{
        TTF_CloseFont(pauseMenuFont);
}

void PauseMenu::DisplayPauseMenu(    float getMouseX, float getMouseY, 
                                    int windowWidth, int windowHeight, 
                                    SDL_Renderer *getRenderer)
{
    // darken background
    SDL_SetRenderDrawColor(getRenderer, 0x00, 0x00, 0x00, 0xAA);
    SDL_FRect backgroundRect = {0, 0, static_cast<float>(windowWidth), 
                                static_cast<float>(windowHeight)};
    SDL_RenderFillRect(getRenderer, &backgroundRect);
}

The Gameplay class only displays its background, which darkens when the game is paused.

#pragma once
#include <SDL3/SDL.h>
#include "pausemenu.h"
#include <iostream>
#include <string>
#include <future>
#include <SDL3_image/SDL_image.h>

class Gameplay
{
public:
    Gameplay(std::string menuFontLocation, std::string backgroundLocation);
    ~Gameplay();
private:
    static int backgroundHeight, backgroundWidth;
    static SDL_Surface *gameplayBackground;

public:
    static PauseMenu *pauseMenu;
public:

    static void ShowBackground(int getWidth, int getHeight, SDL_Renderer *getRenderer);

};

#include "gameplay.h"

int Gameplay::backgroundHeight = 0;
int Gameplay::backgroundWidth = 0;
SDL_Surface *Gameplay::gameplayBackground = nullptr;
PauseMenu *Gameplay::pauseMenu = nullptr;

Gameplay::Gameplay(std::string menuFontLocation, std::string backgroundLocation)
{
    pauseMenu = new PauseMenu(menuFontLocation);

    auto getImageBackground = std::async(std::launch::async, IMG_Load, backgroundLocation.c_str());
    getImageBackground.wait();
    gameplayBackground = getImageBackground.get();

}

Gameplay::~Gameplay()
{
    SDL_DestroySurface(gameplayBackground);
}

void Gameplay::ShowBackground(int getWidth, int getHeight, SDL_Renderer *getRenderer)
{
    SDL_Surface *convert = SDL_ConvertSurface(gameplayBackground, gameplayBackground->format);
    SDL_Texture *backgroundImageTexture = SDL_CreateTextureFromSurface(getRenderer, convert);
    const SDL_FRect backgroundHolder = {0, 0, 
                                        static_cast<float>(getWidth), 
                                        static_cast<float>(getHeight)};
    SDL_RenderTexture(getRenderer, backgroundImageTexture, nullptr, &backgroundHolder);

    SDL_DestroySurface(convert);
    SDL_DestroyTexture(backgroundImageTexture);
}

That's what I got so far. I am looking forward to do more!