From a86a3c170a317cb5963f4c7954bc100a40dbb7f6 Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Mon, 29 Jan 2024 10:26:05 +0100 Subject: [PATCH] start screen working --- CMakeLists.txt | 5 ++-- src/Game.h | 13 +++++++--- src/StartScreen.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++ src/TextScreen.h | 26 ++++++++++++++----- 4 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 src/StartScreen.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8868cd8..c889a60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ find_package(SDL2 REQUIRED) include_directories(${SDL2_INCLUDE_DIRS}) # SDL2 Gfx -find_library(SDL2_GFX_LIBRARY NAMES SDL2_gfx SDL2_gfxd) +find_library(SDL2_GFX_LIBRARY NAMES SDL2_gfx SDL2_gfxd libSDL2_gfx) if (NOT SDL2_GFX_LIBRARY) message(FATAL_ERROR "SDL2_gfx not found") endif () @@ -34,7 +34,8 @@ add_executable(Pong src/main.cpp src/VisibleObjects/Side.h src/VisibleObjects/Score.h src/TextScreen.h - src/defaultfont.h) + src/defaultfont.h + src/StartScreen.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 8e8ca27..c8e49fd 100644 --- a/src/Game.h +++ b/src/Game.h @@ -10,6 +10,7 @@ #include "VisibleObjects/PlayerPaddle.h" #include "VisibleObjects/Score.h" #include "TextScreen.h" +#include "StartScreen.h" enum class GameState { START_SCREEN, GAME, END_SCREEN @@ -20,7 +21,8 @@ private: Ball *ball; Score *score; PlayerPaddle *leftPaddle, *rightPaddle; - TextScreen *startScreen, *endScreen; + StartScreen *startScreen; + TextScreen *endScreen; protected: GameState gameState; @@ -37,7 +39,7 @@ public: }; score = new Score(5, &this->screenSize, func); ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score); - startScreen = new TextScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize); + startScreen = new StartScreen(&this->screenSize, 4); endScreen = new TextScreen("", &this->screenSize); gameState = GameState::START_SCREEN; } @@ -76,6 +78,8 @@ public: switch (gameState) { case GameState::START_SCREEN: startScreen->update(); + if (startScreen->isDone()) + gameState = GameState::GAME; break; case GameState::GAME: ball->update(); @@ -97,8 +101,9 @@ public: switch (gameState) { case GameState::START_SCREEN: - if (event.type == SDL_KEYDOWN) - gameState = GameState::GAME; + if (event.type == SDL_KEYDOWN && !startScreen->hasStartedCounting()) + startScreen->startCountDown(); + return true; case GameState::GAME: handleGameEvent(event); diff --git a/src/StartScreen.h b/src/StartScreen.h new file mode 100644 index 0000000..4f1da49 --- /dev/null +++ b/src/StartScreen.h @@ -0,0 +1,64 @@ +// +// Created by Love on 2024-01-29. +// + +#pragma once + +#include "TextScreen.h" +#include "chrono" + +int_least64_t getCurrentEpochTimeMillis() { + auto now = std::chrono::system_clock::now(); + auto now_ms = std::chrono::time_point_cast(now); + auto epoch = now_ms.time_since_epoch(); + auto value = std::chrono::duration_cast(epoch); + return value.count(); +} + + +class StartScreen : public TextScreen { +private: + bool hasStartedCounting_ = false; + int_least64_t nextMsEpoch = 0; + int stepsToDo, stepsDone = 0; + bool isDone_ = false; +public: + [[nodiscard]] const bool &isDone() const { + return isDone_; + } + + [[nodiscard]] const bool &hasStartedCounting() const { + return hasStartedCounting_; + } + +public: + StartScreen(SDL_Point *screenSize, int seconds) + : TextScreen("Welcome to Pong!\nPress any key to get started...", screenSize), stepsToDo(seconds) { + } + + void update() override { + auto now = getCurrentEpochTimeMillis(); + if (hasStartedCounting_ && nextMsEpoch <= now) { + if (stepsDone < stepsToDo) { + std::string s = std::to_string(stepsToDo - stepsDone); + setText(s); + nextMsEpoch = now + 1000; + hasUpdated = false; + stepsDone++; + } else { + isDone_ = true; + } + } + + TextScreen::update(); + } + + void startCountDown() { + auto epochMs = getCurrentEpochTimeMillis(); + nextMsEpoch = epochMs + 1000; + hasStartedCounting_ = true; + stepsDone = 0; + } + +}; + diff --git a/src/TextScreen.h b/src/TextScreen.h index ae51864..8b384ae 100644 --- a/src/TextScreen.h +++ b/src/TextScreen.h @@ -16,7 +16,7 @@ class TextScreen { private: std::vector lines; TTF_Font *font; - bool hasUpdated; + SDL_Point *screenSize; // Regular std::vector positions; @@ -29,13 +29,16 @@ private: std::vector shadowSurfaces; const int shadowOffset = 3; +protected: + bool hasUpdated; + 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) { + TextScreen(const std::string &text, SDL_Point *screenSize) : hasUpdated(false), screenSize(screenSize) { if (defaultFontPath == nullptr) { std::cerr << "Font path is not set for this platform (null)" << std::endl; exit(-1); @@ -46,7 +49,17 @@ public: exit(-1); } + initPositions(text); + } + +private: + void initPositions(const std::string &text) { lines = splitString(text, '\n'); + surfaces.clear(); + shadowSurfaces.clear(); + positions.clear(); + shadowPositions.clear(); + surfaces.reserve(lines.size()); shadowSurfaces.reserve(lines.size()); positions.reserve(lines.size()); @@ -67,9 +80,9 @@ public: positions.push_back(regularPosition); shadowPositions.push_back(shadowPosition); } - } +public: ~TextScreen() { if (font) TTF_CloseFont(font); @@ -80,7 +93,7 @@ public: } - void draw(SDL_Renderer *renderer) { + virtual void draw(SDL_Renderer *renderer) { for (int i = 0; i < surfaces.size(); ++i) { // Draw shadow SDL_Texture *shadowTexture = SDL_CreateTextureFromSurface(renderer, shadowSurfaces[i]); @@ -98,8 +111,9 @@ public: } } - void setText(std::string &replaceText) { + void setText(const std::string &replaceText) { lines = splitString(replaceText, '\n'); + initPositions(replaceText); } void replaceCharAtIndex(char c, int line, int index) { @@ -118,7 +132,7 @@ public: lines[line][index] = c; } - void update() { + virtual void update() { if (hasUpdated) return;