mirror of
https://github.com/lov3b/Pong.git
synced 2025-01-18 20:50: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/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);
|
Loading…
x
Reference in New Issue
Block a user