From b002cb62e5ecb883478e1060e490ddd86e839774 Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Mon, 29 Jan 2024 12:13:18 +0100 Subject: [PATCH] Merge all text elements + endscreen working --- CMakeLists.txt | 6 +- src/Game.h | 32 +++++---- src/VisibleObjects/Ball.h | 3 +- src/VisibleObjects/Score.h | 128 ---------------------------------- src/{ => text}/OptionScreen.h | 6 +- src/text/Score.h | 71 +++++++++++++++++++ src/{ => text}/TextScreen.h | 26 +++---- 7 files changed, 114 insertions(+), 158 deletions(-) delete mode 100644 src/VisibleObjects/Score.h rename src/{ => text}/OptionScreen.h (86%) create mode 100644 src/text/Score.h rename src/{ => text}/TextScreen.h (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46b8cea..29e7b77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,10 +32,10 @@ add_executable(Pong src/main.cpp src/Vec2d/Bump.h src/VisibleObjects/PlayerPaddle.h src/VisibleObjects/Side.h - src/VisibleObjects/Score.h - src/TextScreen.h + src/text/TextScreen.h src/defaultfont.h - src/OptionScreen.h) + src/text/OptionScreen.h + src/text/Score.h) # Now link the libraries to the target target_link_libraries(Pong ${SDL2_LIBRARIES} ${SDL2_GFX_LIBRARY} ${SDL2_TTF_LIBRARY}) diff --git a/src/Game.h b/src/Game.h index aa09887..d541eac 100644 --- a/src/Game.h +++ b/src/Game.h @@ -8,9 +8,10 @@ #include "SDL.h" #include "VisibleObjects/Ball.h" #include "VisibleObjects/PlayerPaddle.h" -#include "VisibleObjects/Score.h" -#include "TextScreen.h" -#include "OptionScreen.h" +#include "text/Score.h" +#include "text/TextScreen.h" +#include "text/OptionScreen.h" +#include "text/Score.h" enum class GameState { START_SCREEN, GAME, END_SCREEN @@ -36,7 +37,7 @@ public: std::cout << "Player " << player << " won" << std::endl; this->running = false; }; - score = new Score(5, &this->screenSize, func); + score = new Score(&this->screenSize, 5, func); ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score); startScreen = new OptionScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize, 4); endScreen = nullptr; @@ -67,6 +68,7 @@ public: rightPaddle->draw(renderer); break; case GameState::END_SCREEN: + endScreen->draw(renderer); break; } @@ -87,13 +89,18 @@ public: leftPaddle->update(); rightPaddle->update(); score->update(); + + if (score->sideWon().has_value()) { + const char *player = score->sideWon().value() == Side::LEFT ? "left" : "right"; + std::stringstream ss; + ss << "The " << player << " player won with " << std::to_string(score->leftScore) << " - " << std::to_string(score->rightScore) + << "\nWould you like to play again?" << "\nIf so, press any button..."; + score->resetScore(); + endScreen = new OptionScreen(ss.str(), &screenSize, 4); + gameState = GameState::END_SCREEN; + } break; case GameState::END_SCREEN: - if (endScreen == nullptr) { - std::stringstream ss; - ss << "Player " << " won" << "\nWould you like to play again?" << "\nIf so, press any button..."; - endScreen = new OptionScreen(ss.str(), &screenSize, 4); - } endScreen->update(); if (endScreen->isDone()) { gameState = GameState::GAME; @@ -115,14 +122,15 @@ public: if (event.type == SDL_KEYDOWN && !startScreen->hasStartedCounting()) startScreen->startCountDown(); - return true; + break; case GameState::GAME: handleGameEvent(event); - return true; + break; case GameState::END_SCREEN: + if (event.type == SDL_KEYDOWN && !endScreen->hasStartedCounting()) + endScreen->startCountDown(); break; } - } return true; diff --git a/src/VisibleObjects/Ball.h b/src/VisibleObjects/Ball.h index 992630b..00373b9 100644 --- a/src/VisibleObjects/Ball.h +++ b/src/VisibleObjects/Ball.h @@ -8,7 +8,8 @@ #include #include #include "optional" -#include "Score.h" +#include "../text/Score.h" +#include "../text/Score.h" class Ball { private: diff --git a/src/VisibleObjects/Score.h b/src/VisibleObjects/Score.h deleted file mode 100644 index 2d9d1fc..0000000 --- a/src/VisibleObjects/Score.h +++ /dev/null @@ -1,128 +0,0 @@ -// -// Created by love on 2024-01-19. -// - -#pragma once - -#include -#include -#include -#include "Side.h" -#include "SDL_ttf.h" -#include "../defaultfont.h" - - -#include -#include -#include - - -class Score { -private: - uint8_t leftScore, rightScore; - const uint8_t MAX_SCORE; - const std::function whenWon; - TTF_Font *font; - bool hasIncremented = false; - - // Regular - SDL_Rect position; - SDL_Color color = {243, 156, 18, 255}; - SDL_Surface *surface = nullptr; - - // Shadow - const SDL_Color shadowColor = {243, 156, 18, 100}; - SDL_Surface *shadowSurface = nullptr; - const int shadowOffset = 3; - -public: - explicit Score(uint8_t max_score, SDL_Point *screenSize, const std::function &whenWon) : MAX_SCORE( - max_score), whenWon(whenWon) { - resetScore(); - if (defaultFontPath == nullptr) { - std::cerr << "Font path is not set for this platform (null)" << std::endl; - exit(-1); - } - - this->font = TTF_OpenFont(defaultFontPath, 42); - if (font == nullptr) { - std::cerr << "Failed to load font: " << TTF_GetError() << std::endl; - exit(-1); - } - - this->position = SDL_Rect{screenSize->x / 2 - 50, 10, 100, 50}; - this->rightScore = this->leftScore = 0; - } - - ~Score() { - if (font) - TTF_CloseFont(font); - SDL_FreeSurface(surface); - } - - void update() { - if (!hasIncremented && surface != nullptr && shadowSurface != nullptr) return; - - SDL_FreeSurface(surface); - SDL_FreeSurface(shadowSurface); - - hasIncremented = false; - char score_text[8]; - sprintf(score_text, "%d - %d", leftScore, rightScore); - - // Create shadow surface - shadowSurface = TTF_RenderText_Solid(font, score_text, shadowColor); - if (shadowSurface == nullptr) { - std::cerr << "Failed to create shadow text surface: " << TTF_GetError() << std::endl; - } - - // Create main text surface - surface = TTF_RenderText_Solid(font, score_text, color); - if (surface == nullptr) { - std::cerr << "Failed to create text surface: " << TTF_GetError() << std::endl; - } - } - - void draw(SDL_Renderer *renderer) { - // Draw shadow - if (shadowSurface != nullptr) { - SDL_Texture *shadowTexture = SDL_CreateTextureFromSurface(renderer, shadowSurface); - if (shadowTexture != nullptr) { - SDL_Rect shadowPosition = {position.x + shadowOffset, position.y + shadowOffset, position.w, - position.h}; - SDL_RenderCopy(renderer, shadowTexture, nullptr, &shadowPosition); - SDL_DestroyTexture(shadowTexture); - } - } - - // Draw text - if (surface != nullptr) { - SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface); - if (texture != nullptr) { - SDL_RenderCopy(renderer, texture, nullptr, &position); - SDL_DestroyTexture(texture); - } - } - } - - void resetScore() { - leftScore = rightScore = 0; - } - - void incrementScore(const Side side) { - hasIncremented = true; - uint8_t temp; - switch (side) { - case Side::LEFT: - temp = ++leftScore; - break; - case Side::RIGHT: - temp = ++rightScore; - break; - } - - if (temp > MAX_SCORE) - whenWon(side); - } - -}; diff --git a/src/OptionScreen.h b/src/text/OptionScreen.h similarity index 86% rename from src/OptionScreen.h rename to src/text/OptionScreen.h index 63f024b..c496b38 100644 --- a/src/OptionScreen.h +++ b/src/text/OptionScreen.h @@ -22,6 +22,7 @@ private: int_least64_t nextMsEpoch = 0; int stepsToDo, stepsDone = 0; bool isDone_ = false; + public: [[nodiscard]] const bool &isDone() const { return isDone_; @@ -32,8 +33,9 @@ public: } public: - OptionScreen(const std::string &text, SDL_Point *screenSize, int seconds) - : TextScreen(text, screenSize), stepsToDo(seconds) { + OptionScreen(const std::string &text, SDL_Point *screenSize, int seconds) : TextScreen(text, screenSize, + std::nullopt), + stepsToDo(seconds) { } void update() override { diff --git a/src/text/Score.h b/src/text/Score.h new file mode 100644 index 0000000..c971dff --- /dev/null +++ b/src/text/Score.h @@ -0,0 +1,71 @@ +// +// Created by Love on 2024-01-29. +// +#pragma once + + +#include "TextScreen.h" +#include +#include +#include +#include "../VisibleObjects/Side.h" +#include "SDL_ttf.h" +#include "../defaultfont.h" +#include +#include +#include + +class Score : public TextScreen { +private: + const uint8_t MAX_SCORE; + const std::function whenWon; + std::optional sideWon_; + +public: + uint8_t leftScore, rightScore; + + [[nodiscard]] const std::optional &sideWon() const { + return sideWon_; + } + +public: + explicit Score(SDL_Point *screenSize, uint8_t max_score, const std::function &whenWon) : MAX_SCORE( + max_score), whenWon(whenWon), leftScore(0), rightScore(0), TextScreen("", screenSize, std::make_optional( + SDL_Point{screenSize->x / 2 - 50, 10})) { + } + + void update() override { + if (hasUpdated) return; + + std::stringstream ss; + ss << std::to_string(leftScore) << " - " << std::to_string(rightScore); + setText(ss.str()); + TextScreen::update(); + + hasUpdated = true; + } + + void resetScore() { + leftScore = rightScore = 0; + sideWon_ = std::nullopt; + hasUpdated = false; + } + + void incrementScore(const Side side) { + hasUpdated = false; + uint8_t incrementedScore; + switch (side) { + case Side::LEFT: + incrementedScore = ++leftScore; + break; + case Side::RIGHT: + incrementedScore = ++rightScore; + break; + } + + if (incrementedScore > MAX_SCORE) + sideWon_ = side; + } + +}; + diff --git a/src/TextScreen.h b/src/text/TextScreen.h similarity index 87% rename from src/TextScreen.h rename to src/text/TextScreen.h index 8b384ae..bc75595 100644 --- a/src/TextScreen.h +++ b/src/text/TextScreen.h @@ -8,28 +8,30 @@ #include #include #include -#include "defaultfont.h" +#include "../defaultfont.h" #include "iostream" class TextScreen { private: - std::vector lines; + std::vector surfaces; + std::vector shadowSurfaces; TTF_Font *font; SDL_Point *screenSize; + std::optional basePosition; // Regular std::vector positions; SDL_Color color = {243, 156, 18, 255}; - std::vector surfaces; // Shadow std::vector shadowPositions; const SDL_Color shadowColor = {243, 156, 18, 100}; - std::vector shadowSurfaces; const int shadowOffset = 3; + protected: + std::vector lines; bool hasUpdated; public: @@ -38,7 +40,8 @@ public: * @param text This class takes care of freeing text * @param screenSize This won't be freed by this class */ - TextScreen(const std::string &text, SDL_Point *screenSize) : hasUpdated(false), screenSize(screenSize) { + TextScreen(const std::string &text, SDL_Point *screenSize, std::optional basePosition) : hasUpdated( + false), screenSize(screenSize), basePosition(basePosition) { if (defaultFontPath == nullptr) { std::cerr << "Font path is not set for this platform (null)" << std::endl; exit(-1); @@ -69,13 +72,12 @@ private: int textWidth, textHeight; TTF_SizeText(font, lines[i].c_str(), &textWidth, &textHeight); - int baseX = (screenSize->x - textWidth) / 2, baseY = (screenSize->y - textHeight * (lines.size())) / 2; - SDL_Rect regularPosition = {baseX, - baseY + textHeight * i, - textWidth, textHeight}; - SDL_Rect shadowPosition = {baseX + shadowOffset, - baseY + textHeight * i + shadowOffset, - textWidth, + SDL_Point base = basePosition.has_value() ? basePosition.value() : SDL_Point{ + (screenSize->x - textWidth) / 2, + static_cast((screenSize->y - textHeight * (lines.size())) / 2)}; + + SDL_Rect regularPosition = {base.x, base.y + textHeight * i, textWidth, textHeight}; + SDL_Rect shadowPosition = {base.x + shadowOffset, base.y + textHeight * i + shadowOffset, textWidth, textHeight}; positions.push_back(regularPosition); shadowPositions.push_back(shadowPosition);