I created 2 new methods to remove a lot of lines of code. The the first method loads the fonts to the memory and the other one instantiates a new TextElement
object. The second method doesn't sound useful but it made the code much more cleaner because it reduced the amount of code that is being repeated and made multi-platform code easier to handle.
But, how did it make things better?
I use many template arguments in the TextElement object, and when combined with the number of arguments the TextElement constructor requires, it's clear that this can lead to readability issues.
new TextElement< SDL_Surface,
SDL_Texture,
SDL_Color,
TTF_Font,
SDL_Renderer,
AudioPlayer<Mix_Chunk>>(windowWidth * posX,
windowHeight * posY,
font,
renderer);
Before creating the method, this code was used repeatedly across three different platforms and text.
TextElement<SDL_Surface, SDL_Texture, SDL_Color,
TTF_Font, SDL_Renderer,
AudioPlayer<Mix_Chunk>> *Game::LoadTextElement( TTF_Font *font, int inputWindowWidth,
int inputWindowHeight, float posX,
float posY )
{
return new TextElement< SDL_Surface,
SDL_Texture,
SDL_Color,
TTF_Font,
SDL_Renderer,
AudioPlayer<Mix_Chunk>>(windowWidth * posX,
windowHeight * posY,
font,
renderer);
}
This is much better.
if (menuStart == nullptr)
{
#ifdef __APPLE__
menuStart = LoadTextElement( menuFont, execpath + std::string("/Contents/Resources/audio/menulightup/lightup.wav"),
windowWidth, windowHeight, 0.428, 0.5);
#endif
#ifdef _WIN64
menuStart = LoadTextElement( menuFont, execpath + std::string("C:/Users/chris/Desktop/Rebuild_Back_Better/resources/audio/menulightup/lightup.wav"),
windowWidth, windowheight, 0.428, 0.5);
#endif
#ifdef __linux__
menuStart = LoadTextElement( menuFont, execpath + std::string("/home/vmware-ubuntu/Desktop/Rebuild_Back_Better/audio/menulightup/lightup.wav"),
windowWidth, windowheight, 0.428, 0.5);
#endif
}
The LoadMenuFonts
method loads the menu's font and is called within the LoadMainMenu()
method to streamline the gameplay loop's switch case.
void Game::LoadMenuFonts(std::string path1, std::string path2)
{
auto getTitleFont = std::async( std::launch::async, LoadFont,
path1,
150);
auto getMenuFont = std::async( std::launch::async, LoadFont,
path2,
60);
getTitleFont.wait();
getMenuFont.wait();
titleFont = getTitleFont.get();
menuFont = getMenuFont.get();
if (titleFont == nullptr)
{
std::cout << "Title font has not loaded" << std::endl;
exit(-1);
}
if (menuFont == nullptr)
{
std::cout << "Menu font has not loaded" << std::endl;
exit(-1);
}
menuFontsLoaded = true;
}
I manage to cut more than 100 lines thanks to these 2 methods.
In addition to everything else, I used multithreading to smoothly fade out the main menu music when the game starts, because I noticed it was stopping abruptly. I used std::thread
, std::join
, and std::this_thread::sleep_for(std::chrono::milliseconds())
along with multiple threads to manage the fade-out effect.
//Switch Case
if (mouseState == LEFT_MOUSE_BUTTON && menuStart->IsMouseHovering(mouseX, mouseY))
{
std::thread t1 (DestroyMainMenu);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (t1.joinable())
{
t1.join();
}
break;
}
// Destroy main menu elements and fade out music
void Game::DestroyMainMenu()
{
currentGameState = GAMEPLAY;
TTF_CloseFont(titleFont);
TTF_CloseFont(menuFont);
delete(menuTitle);
menuTitle = nullptr;
delete(menuStart);
menuStart = nullptr;
delete(menuContinue);
menuContinue = nullptr;
delete(menuExit);
menuExit = nullptr;
menuFontsLoaded = false;
haveElementsLoaded = false;
std::thread t2(menuMusic->StopAudio, 500);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (t2.joinable())
{
t2.join();
}
menuMusic->plays = false;
}
The main thread pauses for 500 milliseconds while the t1
thread runs the StopAudio
method on another thread named t2
. Then, t1
waits another 500 milliseconds to allow the fade-out effect to finish. Once t2
completes the operation, it joins t1
, and then t1
joins the main thread, allowing the game loop to proceed normally.