Merge all text elements + endscreen working

This commit is contained in:
Love 2024-01-29 12:13:18 +01:00
parent 18ce5670e4
commit b002cb62e5
7 changed files with 114 additions and 158 deletions

View File

@ -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})

View File

@ -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;

View File

@ -8,7 +8,8 @@
#include <SDL2/SDL2_gfxPrimitives.h>
#include <iostream>
#include "optional"
#include "Score.h"
#include "../text/Score.h"
#include "../text/Score.h"
class Ball {
private:

View File

@ -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);
}
};

View File

@ -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 {

71
src/text/Score.h Normal file
View 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;
}
};

View File

@ -8,28 +8,30 @@
#include <SDL_ttf.h>
#include <utility>
#include <vector>
#include "defaultfont.h"
#include "../defaultfont.h"
#include "iostream"
class TextScreen {
private:
std::vector<std::string> lines;
std::vector<SDL_Surface *> surfaces;
std::vector<SDL_Surface *> shadowSurfaces;
TTF_Font *font;
SDL_Point *screenSize;
std::optional<SDL_Point> basePosition;
// Regular
std::vector<SDL_Rect> positions;
SDL_Color color = {243, 156, 18, 255};
std::vector<SDL_Surface *> surfaces;
// Shadow
std::vector<SDL_Rect> shadowPositions;
const SDL_Color shadowColor = {243, 156, 18, 100};
std::vector<SDL_Surface *> shadowSurfaces;
const int shadowOffset = 3;
protected:
std::vector<std::string> 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<SDL_Point> 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<int>((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);