mirror of
https://github.com/lov3b/Pong.git
synced 2025-01-18 12:40:12 +01:00
Merge all text elements + endscreen working
This commit is contained in:
parent
18ce5670e4
commit
b002cb62e5
@ -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})
|
||||
|
32
src/Game.h
32
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;
|
||||
|
@ -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:
|
||||
|
@ -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 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
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 <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);
|
Loading…
x
Reference in New Issue
Block a user