mirror of
https://github.com/lov3b/Pong.git
synced 2025-01-18 20:50:12 +01:00
start screen text
This commit is contained in:
parent
f958b4b5ec
commit
5c87e2d918
91
src/Game.h
91
src/Game.h
@ -9,6 +9,7 @@
|
|||||||
#include "VisibleObjects/Ball.h"
|
#include "VisibleObjects/Ball.h"
|
||||||
#include "VisibleObjects/PlayerPaddle.h"
|
#include "VisibleObjects/PlayerPaddle.h"
|
||||||
#include "VisibleObjects/Score.h"
|
#include "VisibleObjects/Score.h"
|
||||||
|
#include "TextScreen.h"
|
||||||
|
|
||||||
enum class GameState {
|
enum class GameState {
|
||||||
START_SCREEN, GAME, END_SCREEN
|
START_SCREEN, GAME, END_SCREEN
|
||||||
@ -19,6 +20,7 @@ private:
|
|||||||
Ball *ball;
|
Ball *ball;
|
||||||
Score *score;
|
Score *score;
|
||||||
PlayerPaddle *leftPaddle, *rightPaddle;
|
PlayerPaddle *leftPaddle, *rightPaddle;
|
||||||
|
TextScreen *startScreen, *endScreen;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GameState gameState;
|
GameState gameState;
|
||||||
@ -35,6 +37,8 @@ public:
|
|||||||
};
|
};
|
||||||
score = new Score(5, &this->screenSize, func);
|
score = new Score(5, &this->screenSize, func);
|
||||||
ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score);
|
ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score);
|
||||||
|
startScreen = new TextScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize);
|
||||||
|
endScreen = new TextScreen("", &this->screenSize);
|
||||||
gameState = GameState::START_SCREEN;
|
gameState = GameState::START_SCREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +57,7 @@ public:
|
|||||||
|
|
||||||
switch (gameState) {
|
switch (gameState) {
|
||||||
case GameState::START_SCREEN:
|
case GameState::START_SCREEN:
|
||||||
|
startScreen->draw(renderer);
|
||||||
break;
|
break;
|
||||||
case GameState::GAME:
|
case GameState::GAME:
|
||||||
ball->draw(renderer);
|
ball->draw(renderer);
|
||||||
@ -67,9 +72,10 @@ public:
|
|||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update() override {
|
void update() override {
|
||||||
switch (gameState) {
|
switch (gameState) {
|
||||||
case GameState::START_SCREEN:
|
case GameState::START_SCREEN:
|
||||||
|
startScreen->update();
|
||||||
break;
|
break;
|
||||||
case GameState::GAME:
|
case GameState::GAME:
|
||||||
ball->update();
|
ball->update();
|
||||||
@ -80,52 +86,67 @@ public:
|
|||||||
case GameState::END_SCREEN:
|
case GameState::END_SCREEN:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleEvents() override {
|
bool handleEvents() override {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event) != 0) {
|
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
if (event.type == SDL_QUIT)
|
if (event.type == SDL_QUIT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (event.type == SDL_KEYDOWN) {
|
switch (gameState) {
|
||||||
switch (event.key.keysym.sym) {
|
case GameState::START_SCREEN:
|
||||||
case SDLK_w:
|
if (event.type == SDL_KEYDOWN)
|
||||||
leftPaddle->startMoving(true);
|
gameState = GameState::GAME;
|
||||||
break;
|
return true;
|
||||||
case SDLK_s:
|
case GameState::GAME:
|
||||||
leftPaddle->startMoving(false);
|
handleGameEvent(event);
|
||||||
break;
|
return true;
|
||||||
|
case GameState::END_SCREEN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SDLK_UP:
|
}
|
||||||
rightPaddle->startMoving(true);
|
|
||||||
break;
|
|
||||||
case SDLK_DOWN:
|
|
||||||
rightPaddle->startMoving(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (event.type == SDL_KEYUP) {
|
|
||||||
switch (event.key.keysym.sym) {
|
|
||||||
case SDLK_w:
|
|
||||||
leftPaddle->stopMoving(true);
|
|
||||||
break;
|
|
||||||
case SDLK_s:
|
|
||||||
leftPaddle->stopMoving(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDLK_UP:
|
return true;
|
||||||
rightPaddle->stopMoving(true);
|
}
|
||||||
break;
|
|
||||||
case SDLK_DOWN:
|
void handleGameEvent(SDL_Event &event) {
|
||||||
rightPaddle->stopMoving(false);
|
if (event.type == SDL_KEYDOWN) {
|
||||||
break;
|
switch (event.key.keysym.sym) {
|
||||||
}
|
case SDLK_w:
|
||||||
|
leftPaddle->startMoving(true);
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
leftPaddle->startMoving(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_UP:
|
||||||
|
rightPaddle->startMoving(true);
|
||||||
|
break;
|
||||||
|
case SDLK_DOWN:
|
||||||
|
rightPaddle->startMoving(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (event.type == SDL_KEYUP) {
|
||||||
|
switch (event.key.keysym.sym) {
|
||||||
|
case SDLK_w:
|
||||||
|
leftPaddle->stopMoving(true);
|
||||||
|
break;
|
||||||
|
case SDLK_s:
|
||||||
|
leftPaddle->stopMoving(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_UP:
|
||||||
|
rightPaddle->stopMoving(true);
|
||||||
|
break;
|
||||||
|
case SDLK_DOWN:
|
||||||
|
rightPaddle->stopMoving(false);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -53,14 +53,15 @@ public:
|
|||||||
|
|
||||||
virtual void draw(SDL_Renderer *renderer) = 0;
|
virtual void draw(SDL_Renderer *renderer) = 0;
|
||||||
|
|
||||||
virtual bool update() = 0;
|
virtual void update() = 0;
|
||||||
|
|
||||||
virtual bool handleEvents() = 0;
|
virtual bool handleEvents() = 0;
|
||||||
|
|
||||||
int loop() {
|
int loop() {
|
||||||
while (running) {
|
while (running) {
|
||||||
if (!handleEvents() || !update())
|
if (!handleEvents())
|
||||||
break;
|
break;
|
||||||
|
update();
|
||||||
draw(renderer);
|
draw(renderer);
|
||||||
SDL_Delay(1000 / fps);
|
SDL_Delay(1000 / fps);
|
||||||
}
|
}
|
||||||
|
128
src/TextScreen.h
128
src/TextScreen.h
@ -6,23 +6,27 @@
|
|||||||
|
|
||||||
#include <SDL_render.h>
|
#include <SDL_render.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include "defaultfont.h"
|
#include "defaultfont.h"
|
||||||
#include "iostream"
|
#include "iostream"
|
||||||
|
|
||||||
|
|
||||||
class TextScreen {
|
class TextScreen {
|
||||||
private:
|
private:
|
||||||
std::string *text;
|
std::vector<std::string> lines;
|
||||||
TTF_Font *font;
|
TTF_Font *font;
|
||||||
bool hasUpdated;
|
bool hasUpdated;
|
||||||
|
|
||||||
// Regular
|
// Regular
|
||||||
SDL_Rect position;
|
std::vector<SDL_Rect> positions;
|
||||||
SDL_Color color = {243, 156, 18, 255};
|
SDL_Color color = {243, 156, 18, 255};
|
||||||
SDL_Surface *surface = nullptr;
|
std::vector<SDL_Surface *> surfaces;
|
||||||
|
|
||||||
// Shadow
|
// Shadow
|
||||||
|
std::vector<SDL_Rect> shadowPositions;
|
||||||
const SDL_Color shadowColor = {243, 156, 18, 100};
|
const SDL_Color shadowColor = {243, 156, 18, 100};
|
||||||
SDL_Surface *shadowSurface = nullptr;
|
std::vector<SDL_Surface *> shadowSurfaces;
|
||||||
const int shadowOffset = 3;
|
const int shadowOffset = 3;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -31,7 +35,7 @@ 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(std::string *text, SDL_Point *screenSize) : text(text), hasUpdated(false) {
|
TextScreen(const std::string& text, SDL_Point *screenSize) : hasUpdated(false) {
|
||||||
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);
|
||||||
@ -41,74 +45,122 @@ public:
|
|||||||
std::cerr << "Failed to load font: " << TTF_GetError() << std::endl;
|
std::cerr << "Failed to load font: " << TTF_GetError() << std::endl;
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
this->position = SDL_Rect{50, 50, screenSize->x - 50, screenSize->y - 50};
|
|
||||||
|
lines = splitString(text, '\n');
|
||||||
|
surfaces.reserve(lines.size());
|
||||||
|
shadowSurfaces.reserve(lines.size());
|
||||||
|
positions.reserve(lines.size());
|
||||||
|
shadowPositions.reserve(lines.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
|
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,
|
||||||
|
textHeight};
|
||||||
|
positions.push_back(regularPosition);
|
||||||
|
shadowPositions.push_back(shadowPosition);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~TextScreen() {
|
~TextScreen() {
|
||||||
if (font)
|
if (font)
|
||||||
TTF_CloseFont(font);
|
TTF_CloseFont(font);
|
||||||
SDL_FreeSurface(surface);
|
for (auto *surface: surfaces)
|
||||||
delete text;
|
SDL_FreeSurface(surface);
|
||||||
|
for (auto *surface: shadowSurfaces)
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void draw(SDL_Renderer *renderer) {
|
void draw(SDL_Renderer *renderer) {
|
||||||
// Draw shadow
|
for (int i = 0; i < surfaces.size(); ++i) {
|
||||||
if (shadowSurface != nullptr) {
|
// Draw shadow
|
||||||
SDL_Texture *shadowTexture = SDL_CreateTextureFromSurface(renderer, shadowSurface);
|
SDL_Texture *shadowTexture = SDL_CreateTextureFromSurface(renderer, shadowSurfaces[i]);
|
||||||
if (shadowTexture != nullptr) {
|
if (shadowTexture != nullptr) {
|
||||||
SDL_Rect shadowPosition = {position.x + shadowOffset, position.y + shadowOffset, position.w,
|
SDL_RenderCopy(renderer, shadowTexture, nullptr, &shadowPositions[i]);
|
||||||
position.h};
|
|
||||||
SDL_RenderCopy(renderer, shadowTexture, nullptr, &shadowPosition);
|
|
||||||
SDL_DestroyTexture(shadowTexture);
|
SDL_DestroyTexture(shadowTexture);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
if (surface != nullptr) {
|
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surfaces[i]);
|
||||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
|
|
||||||
if (texture != nullptr) {
|
if (texture != nullptr) {
|
||||||
SDL_RenderCopy(renderer, texture, nullptr, &position);
|
SDL_RenderCopy(renderer, texture, nullptr, &positions[i]);
|
||||||
SDL_DestroyTexture(texture);
|
SDL_DestroyTexture(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setText(std::string *replaceText) {
|
void setText(std::string &replaceText) {
|
||||||
delete this->text;
|
lines = splitString(replaceText, '\n');
|
||||||
this->text = replaceText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void replaceCharAtIndex(char c, int index) {
|
void replaceCharAtIndex(char c, int line, int index) {
|
||||||
if (text->length() <= index) {
|
if (lines.size() <= line) {
|
||||||
std::cerr << "text string is at length " << text->length() << ", but index is " << index << std::endl;
|
if (lines[line].length() <= index) {
|
||||||
|
std::cerr << "string lines is of length " << lines.size() << ", but line index is " << index
|
||||||
|
<< std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lines[line].length() <= index) {
|
||||||
|
std::cerr << "text string is of length " << lines[line].length() << ", but index is " << index << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hasUpdated = false;
|
hasUpdated = false;
|
||||||
text[index] = c;
|
lines[line][index] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
if (!hasUpdated)
|
if (hasUpdated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SDL_FreeSurface(surface);
|
for (auto &surface: surfaces)
|
||||||
SDL_FreeSurface(shadowSurface);
|
SDL_FreeSurface(surface);
|
||||||
|
for (auto &shadowSurface: shadowSurfaces)
|
||||||
|
SDL_FreeSurface(shadowSurface);
|
||||||
|
surfaces.clear();
|
||||||
|
shadowSurfaces.clear();
|
||||||
|
|
||||||
shadowSurface = TTF_RenderText_Solid(font, text->c_str(), shadowColor);
|
for (const auto &line: lines) {
|
||||||
if (shadowSurface == nullptr)
|
SDL_Surface *textSurface = TTF_RenderText_Solid(font, line.c_str(), color);
|
||||||
std::cerr << "Failed to create shadow text surface (TextScreen): " << TTF_GetError() << std::endl;
|
SDL_Surface *shadowSurface = TTF_RenderText_Solid(font, line.c_str(), shadowColor);
|
||||||
|
|
||||||
surface = TTF_RenderText_Solid(font, text->c_str(), color);
|
if (textSurface == nullptr || shadowSurface == nullptr) {
|
||||||
if (surface == nullptr)
|
std::cerr << "Failed to create text surface (TextScreen): " << TTF_GetError() << std::endl;
|
||||||
std::cerr << "Failed to create text surface (TextScreen): " << TTF_GetError() << std::endl;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
surfaces.push_back(textSurface);
|
||||||
|
shadowSurfaces.push_back(shadowSurface);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
hasUpdated = true;
|
hasUpdated = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gameContextFinished() {
|
private:
|
||||||
|
static std::vector<std::string> splitString(const std::string &string, const char delim) {
|
||||||
|
int size = 0;
|
||||||
|
for (char c: string)
|
||||||
|
if (c == delim) size++;
|
||||||
|
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
lines.reserve(size);
|
||||||
|
|
||||||
|
std::stringstream ss(string);
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(ss, line, delim))
|
||||||
|
lines.push_back(line);
|
||||||
|
|
||||||
|
|
||||||
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user