Rebuild Back Better
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!
Subscribe to my newsletter
Read articles from Chris Douris directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Chris Douris
Chris Douris
AKA Chris, is a software developer from Athens, Greece. He started programming with basic when he was very young. He lost interest in programming during school years but after an unsuccessful career in audio, he decided focus on what he really loves which is technology. He loves working with older languages like C and wants to start programming electronics and microcontrollers because he wants to get into embedded systems programming.