mirror of
				https://github.com/lov3b/Pong.git
				synced 2025-10-30 12:50:28 +01:00 
			
		
		
		
	Merge all text elements + endscreen working
This commit is contained in:
		| @@ -32,10 +32,10 @@ add_executable(Pong src/main.cpp | |||||||
|         src/Vec2d/Bump.h |         src/Vec2d/Bump.h | ||||||
|         src/VisibleObjects/PlayerPaddle.h |         src/VisibleObjects/PlayerPaddle.h | ||||||
|         src/VisibleObjects/Side.h |         src/VisibleObjects/Side.h | ||||||
|         src/VisibleObjects/Score.h |         src/text/TextScreen.h | ||||||
|         src/TextScreen.h |  | ||||||
|         src/defaultfont.h |         src/defaultfont.h | ||||||
|         src/OptionScreen.h) |         src/text/OptionScreen.h | ||||||
|  |         src/text/Score.h) | ||||||
|  |  | ||||||
| # Now link the libraries to the target | # Now link the libraries to the target | ||||||
| target_link_libraries(Pong ${SDL2_LIBRARIES} ${SDL2_GFX_LIBRARY} ${SDL2_TTF_LIBRARY}) | target_link_libraries(Pong ${SDL2_LIBRARIES} ${SDL2_GFX_LIBRARY} ${SDL2_TTF_LIBRARY}) | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								src/Game.h
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/Game.h
									
									
									
									
									
								
							| @@ -8,9 +8,10 @@ | |||||||
| #include "SDL.h" | #include "SDL.h" | ||||||
| #include "VisibleObjects/Ball.h" | #include "VisibleObjects/Ball.h" | ||||||
| #include "VisibleObjects/PlayerPaddle.h" | #include "VisibleObjects/PlayerPaddle.h" | ||||||
| #include "VisibleObjects/Score.h" | #include "text/Score.h" | ||||||
| #include "TextScreen.h" | #include "text/TextScreen.h" | ||||||
| #include "OptionScreen.h" | #include "text/OptionScreen.h" | ||||||
|  | #include "text/Score.h" | ||||||
|  |  | ||||||
| enum class GameState { | enum class GameState { | ||||||
|     START_SCREEN, GAME, END_SCREEN |     START_SCREEN, GAME, END_SCREEN | ||||||
| @@ -36,7 +37,7 @@ public: | |||||||
|             std::cout << "Player " << player << " won" << std::endl; |             std::cout << "Player " << player << " won" << std::endl; | ||||||
|             this->running = false; |             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); |         ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score); | ||||||
|         startScreen = new OptionScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize, 4); |         startScreen = new OptionScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize, 4); | ||||||
|         endScreen = nullptr; |         endScreen = nullptr; | ||||||
| @@ -67,6 +68,7 @@ public: | |||||||
|                 rightPaddle->draw(renderer); |                 rightPaddle->draw(renderer); | ||||||
|                 break; |                 break; | ||||||
|             case GameState::END_SCREEN: |             case GameState::END_SCREEN: | ||||||
|  |                 endScreen->draw(renderer); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -87,13 +89,18 @@ public: | |||||||
|                 leftPaddle->update(); |                 leftPaddle->update(); | ||||||
|                 rightPaddle->update(); |                 rightPaddle->update(); | ||||||
|                 score->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; |                 break; | ||||||
|             case GameState::END_SCREEN: |             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(); |                 endScreen->update(); | ||||||
|                 if (endScreen->isDone()) { |                 if (endScreen->isDone()) { | ||||||
|                     gameState = GameState::GAME; |                     gameState = GameState::GAME; | ||||||
| @@ -115,14 +122,15 @@ public: | |||||||
|                     if (event.type == SDL_KEYDOWN && !startScreen->hasStartedCounting()) |                     if (event.type == SDL_KEYDOWN && !startScreen->hasStartedCounting()) | ||||||
|                         startScreen->startCountDown(); |                         startScreen->startCountDown(); | ||||||
|  |  | ||||||
|                     return true; |                     break; | ||||||
|                 case GameState::GAME: |                 case GameState::GAME: | ||||||
|                     handleGameEvent(event); |                     handleGameEvent(event); | ||||||
|                     return true; |                     break; | ||||||
|                 case GameState::END_SCREEN: |                 case GameState::END_SCREEN: | ||||||
|  |                     if (event.type == SDL_KEYDOWN && !endScreen->hasStartedCounting()) | ||||||
|  |                         endScreen->startCountDown(); | ||||||
|                     break; |                     break; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|   | |||||||
| @@ -8,7 +8,8 @@ | |||||||
| #include <SDL2/SDL2_gfxPrimitives.h> | #include <SDL2/SDL2_gfxPrimitives.h> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include "optional" | #include "optional" | ||||||
| #include "Score.h" | #include "../text/Score.h" | ||||||
|  | #include "../text/Score.h" | ||||||
|  |  | ||||||
| class Ball { | class Ball { | ||||||
| private: | private: | ||||||
|   | |||||||
| @@ -1,128 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by love on 2024-01-19. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <cstdint> |  | ||||||
| #include <SDL_render.h> |  | ||||||
| #include <functional> |  | ||||||
| #include "Side.h" |  | ||||||
| #include "SDL_ttf.h" |  | ||||||
| #include "../defaultfont.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <SDL_ttf.h> |  | ||||||
| #include <string> |  | ||||||
| #include <iostream> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Score { |  | ||||||
| private: |  | ||||||
|     uint8_t leftScore, rightScore; |  | ||||||
|     const uint8_t MAX_SCORE; |  | ||||||
|     const std::function<void(Side)> 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<void(Side)> &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); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| }; |  | ||||||
| @@ -22,6 +22,7 @@ private: | |||||||
|     int_least64_t nextMsEpoch = 0; |     int_least64_t nextMsEpoch = 0; | ||||||
|     int stepsToDo, stepsDone = 0; |     int stepsToDo, stepsDone = 0; | ||||||
|     bool isDone_ = false; |     bool isDone_ = false; | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|     [[nodiscard]] const bool &isDone() const { |     [[nodiscard]] const bool &isDone() const { | ||||||
|         return isDone_; |         return isDone_; | ||||||
| @@ -32,8 +33,9 @@ public: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     OptionScreen(const std::string &text, SDL_Point *screenSize, int seconds) |     OptionScreen(const std::string &text, SDL_Point *screenSize, int seconds) : TextScreen(text, screenSize, | ||||||
|             : TextScreen(text, screenSize), stepsToDo(seconds) { |                                                                                            std::nullopt), | ||||||
|  |                                                                                 stepsToDo(seconds) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void update() override { |     void update() override { | ||||||
							
								
								
									
										71
									
								
								src/text/Score.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/text/Score.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | // | ||||||
|  | // Created by Love on 2024-01-29. | ||||||
|  | // | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #include "TextScreen.h" | ||||||
|  | #include <cstdint> | ||||||
|  | #include <SDL_render.h> | ||||||
|  | #include <functional> | ||||||
|  | #include "../VisibleObjects/Side.h" | ||||||
|  | #include "SDL_ttf.h" | ||||||
|  | #include "../defaultfont.h" | ||||||
|  | #include <string> | ||||||
|  | #include <iostream> | ||||||
|  | #include <optional> | ||||||
|  |  | ||||||
|  | class Score : public TextScreen { | ||||||
|  | private: | ||||||
|  |     const uint8_t MAX_SCORE; | ||||||
|  |     const std::function<void(Side)> whenWon; | ||||||
|  |     std::optional<Side> sideWon_; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     uint8_t leftScore, rightScore; | ||||||
|  |  | ||||||
|  |     [[nodiscard]] const std::optional<Side> &sideWon() const { | ||||||
|  |         return sideWon_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     explicit Score(SDL_Point *screenSize, uint8_t max_score, const std::function<void(Side)> &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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
| @@ -8,28 +8,30 @@ | |||||||
| #include <SDL_ttf.h> | #include <SDL_ttf.h> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "defaultfont.h" | #include "../defaultfont.h" | ||||||
| #include "iostream" | #include "iostream" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TextScreen { | class TextScreen { | ||||||
| private: | private: | ||||||
|     std::vector<std::string> lines; |     std::vector<SDL_Surface *> surfaces; | ||||||
|  |     std::vector<SDL_Surface *> shadowSurfaces; | ||||||
|     TTF_Font *font; |     TTF_Font *font; | ||||||
|     SDL_Point *screenSize; |     SDL_Point *screenSize; | ||||||
|  |     std::optional<SDL_Point> basePosition; | ||||||
| 
 | 
 | ||||||
|     // Regular
 |     // Regular
 | ||||||
|     std::vector<SDL_Rect> positions; |     std::vector<SDL_Rect> positions; | ||||||
|     SDL_Color color = {243, 156, 18, 255}; |     SDL_Color color = {243, 156, 18, 255}; | ||||||
|     std::vector<SDL_Surface *> surfaces; |  | ||||||
| 
 | 
 | ||||||
|     // Shadow
 |     // Shadow
 | ||||||
|     std::vector<SDL_Rect> shadowPositions; |     std::vector<SDL_Rect> shadowPositions; | ||||||
|     const SDL_Color shadowColor = {243, 156, 18, 100}; |     const SDL_Color shadowColor = {243, 156, 18, 100}; | ||||||
|     std::vector<SDL_Surface *> shadowSurfaces; |  | ||||||
|     const int shadowOffset = 3; |     const int shadowOffset = 3; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|  |     std::vector<std::string> lines; | ||||||
|     bool hasUpdated; |     bool hasUpdated; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| @@ -38,7 +40,8 @@ public: | |||||||
|      * @param text This class takes care of freeing text |      * @param text This class takes care of freeing text | ||||||
|      * @param screenSize This won't be freed by this class |      * @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<SDL_Point> basePosition) : hasUpdated( | ||||||
|  |             false), screenSize(screenSize), basePosition(basePosition) { | ||||||
|         if (defaultFontPath == nullptr) { |         if (defaultFontPath == nullptr) { | ||||||
|             std::cerr << "Font path is not set for this platform (null)" << std::endl; |             std::cerr << "Font path is not set for this platform (null)" << std::endl; | ||||||
|             exit(-1); |             exit(-1); | ||||||
| @@ -69,13 +72,12 @@ private: | |||||||
|             int textWidth, textHeight; |             int textWidth, textHeight; | ||||||
|             TTF_SizeText(font, lines[i].c_str(), &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_Point base = basePosition.has_value() ? basePosition.value() : SDL_Point{ | ||||||
|             SDL_Rect regularPosition = {baseX, |                     (screenSize->x - textWidth) / 2, | ||||||
|                                         baseY + textHeight * i, |                     static_cast<int>((screenSize->y - textHeight * (lines.size())) / 2)}; | ||||||
|                                         textWidth, textHeight}; | 
 | ||||||
|             SDL_Rect shadowPosition = {baseX + shadowOffset, |             SDL_Rect regularPosition = {base.x, base.y + textHeight * i, textWidth, textHeight}; | ||||||
|                                        baseY + textHeight * i + shadowOffset, |             SDL_Rect shadowPosition = {base.x + shadowOffset, base.y + textHeight * i + shadowOffset, textWidth, | ||||||
|                                        textWidth, |  | ||||||
|                                        textHeight}; |                                        textHeight}; | ||||||
|             positions.push_back(regularPosition); |             positions.push_back(regularPosition); | ||||||
|             shadowPositions.push_back(shadowPosition); |             shadowPositions.push_back(shadowPosition); | ||||||
		Reference in New Issue
	
	Block a user