2024-01-19 15:06:48 +01:00
|
|
|
//
|
|
|
|
// Created by love on 2024-01-18.
|
|
|
|
//
|
|
|
|
|
|
|
|
#pragma
|
|
|
|
|
|
|
|
#include "SdlWrapper.h"
|
|
|
|
#include "SDL.h"
|
|
|
|
#include "VisibleObjects/Ball.h"
|
|
|
|
#include "VisibleObjects/PlayerPaddle.h"
|
2024-01-29 12:13:18 +01:00
|
|
|
#include "text/Score.h"
|
|
|
|
#include "text/TextScreen.h"
|
|
|
|
#include "text/OptionScreen.h"
|
|
|
|
#include "text/Score.h"
|
2024-01-19 15:06:48 +01:00
|
|
|
|
2024-01-28 21:07:18 +01:00
|
|
|
enum class GameState {
|
|
|
|
START_SCREEN, GAME, END_SCREEN
|
|
|
|
};
|
2024-01-19 15:06:48 +01:00
|
|
|
|
|
|
|
class Game : public SdlWrapper {
|
|
|
|
private:
|
|
|
|
Ball *ball;
|
2024-01-19 18:41:26 +01:00
|
|
|
Score *score;
|
2024-01-19 15:06:48 +01:00
|
|
|
PlayerPaddle *leftPaddle, *rightPaddle;
|
2024-01-29 10:46:27 +01:00
|
|
|
OptionScreen *startScreen, *endScreen;
|
2024-01-19 15:06:48 +01:00
|
|
|
|
2024-01-28 21:07:18 +01:00
|
|
|
protected:
|
|
|
|
GameState gameState;
|
|
|
|
|
2024-01-19 15:06:48 +01:00
|
|
|
public:
|
|
|
|
explicit Game(SDL_Point screenSize) : SdlWrapper("Pong", screenSize, 60) {
|
|
|
|
leftPaddle = new PlayerPaddle(&this->screenSize, Side::LEFT);
|
|
|
|
rightPaddle = new PlayerPaddle(&this->screenSize, Side::RIGHT);
|
2024-01-19 18:41:26 +01:00
|
|
|
|
|
|
|
auto func = [this](Side side) {
|
|
|
|
const char *player = side == Side::LEFT ? "one" : "two";
|
|
|
|
std::cout << "Player " << player << " won" << std::endl;
|
|
|
|
this->running = false;
|
|
|
|
};
|
2024-01-29 12:13:18 +01:00
|
|
|
score = new Score(&this->screenSize, 5, func);
|
2024-01-19 18:41:26 +01:00
|
|
|
ball = new Ball(&this->screenSize, leftPaddle, rightPaddle, score);
|
2024-01-29 10:46:27 +01:00
|
|
|
startScreen = new OptionScreen("Welcome to Pong!\nPress any key to get started...", &this->screenSize, 4);
|
|
|
|
endScreen = nullptr;
|
2024-01-28 21:07:18 +01:00
|
|
|
gameState = GameState::START_SCREEN;
|
2024-01-19 15:06:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~Game() override {
|
|
|
|
delete ball;
|
|
|
|
delete leftPaddle;
|
|
|
|
delete rightPaddle;
|
2024-01-19 18:41:26 +01:00
|
|
|
delete score;
|
2024-01-19 15:06:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void draw(SDL_Renderer *renderer) override {
|
|
|
|
// Background
|
|
|
|
SDL_SetRenderDrawColor(renderer, 128, 0, 128, 0);
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
|
2024-01-28 21:07:18 +01:00
|
|
|
|
|
|
|
switch (gameState) {
|
|
|
|
case GameState::START_SCREEN:
|
2024-01-29 00:43:01 +01:00
|
|
|
startScreen->draw(renderer);
|
2024-01-28 21:07:18 +01:00
|
|
|
break;
|
|
|
|
case GameState::GAME:
|
|
|
|
ball->draw(renderer);
|
|
|
|
score->draw(renderer);
|
|
|
|
leftPaddle->draw(renderer);
|
|
|
|
rightPaddle->draw(renderer);
|
|
|
|
break;
|
|
|
|
case GameState::END_SCREEN:
|
2024-01-29 12:13:18 +01:00
|
|
|
endScreen->draw(renderer);
|
2024-01-28 21:07:18 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-01-19 15:06:48 +01:00
|
|
|
SDL_RenderPresent(renderer);
|
|
|
|
}
|
|
|
|
|
2024-01-29 00:43:01 +01:00
|
|
|
void update() override {
|
2024-01-28 21:07:18 +01:00
|
|
|
switch (gameState) {
|
|
|
|
case GameState::START_SCREEN:
|
2024-01-29 00:43:01 +01:00
|
|
|
startScreen->update();
|
2024-01-29 10:46:27 +01:00
|
|
|
if (startScreen->isDone()) {
|
2024-01-29 10:26:05 +01:00
|
|
|
gameState = GameState::GAME;
|
2024-01-29 10:46:27 +01:00
|
|
|
delete startScreen; // We will never get back to this state
|
|
|
|
}
|
2024-01-28 21:07:18 +01:00
|
|
|
break;
|
|
|
|
case GameState::GAME:
|
|
|
|
ball->update();
|
|
|
|
leftPaddle->update();
|
|
|
|
rightPaddle->update();
|
|
|
|
score->update();
|
2024-01-29 12:13:18 +01:00
|
|
|
|
|
|
|
if (score->sideWon().has_value()) {
|
|
|
|
const char *player = score->sideWon().value() == Side::LEFT ? "left" : "right";
|
2024-01-29 10:46:27 +01:00
|
|
|
std::stringstream ss;
|
2024-01-29 12:13:18 +01:00
|
|
|
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();
|
2024-01-29 10:46:27 +01:00
|
|
|
endScreen = new OptionScreen(ss.str(), &screenSize, 4);
|
2024-01-29 12:13:18 +01:00
|
|
|
gameState = GameState::END_SCREEN;
|
2024-01-29 10:46:27 +01:00
|
|
|
}
|
2024-01-29 12:13:18 +01:00
|
|
|
break;
|
|
|
|
case GameState::END_SCREEN:
|
2024-01-29 10:46:27 +01:00
|
|
|
endScreen->update();
|
|
|
|
if (endScreen->isDone()) {
|
|
|
|
gameState = GameState::GAME;
|
|
|
|
delete endScreen; // The text will not be the same if we get back here. We might as well free it.
|
|
|
|
}
|
2024-01-28 21:07:18 +01:00
|
|
|
break;
|
|
|
|
}
|
2024-01-19 15:06:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool handleEvents() override {
|
|
|
|
SDL_Event event;
|
2024-01-29 00:43:01 +01:00
|
|
|
|
|
|
|
while (SDL_PollEvent(&event)) {
|
2024-01-19 15:06:48 +01:00
|
|
|
if (event.type == SDL_QUIT)
|
|
|
|
return false;
|
|
|
|
|
2024-01-29 00:43:01 +01:00
|
|
|
switch (gameState) {
|
|
|
|
case GameState::START_SCREEN:
|
2024-01-29 10:26:05 +01:00
|
|
|
if (event.type == SDL_KEYDOWN && !startScreen->hasStartedCounting())
|
|
|
|
startScreen->startCountDown();
|
|
|
|
|
2024-01-29 12:13:18 +01:00
|
|
|
break;
|
2024-01-29 00:43:01 +01:00
|
|
|
case GameState::GAME:
|
|
|
|
handleGameEvent(event);
|
2024-01-29 12:13:18 +01:00
|
|
|
break;
|
2024-01-29 00:43:01 +01:00
|
|
|
case GameState::END_SCREEN:
|
2024-01-29 12:13:18 +01:00
|
|
|
if (event.type == SDL_KEYDOWN && !endScreen->hasStartedCounting())
|
|
|
|
endScreen->startCountDown();
|
2024-01-29 00:43:01 +01:00
|
|
|
break;
|
2024-01-19 15:06:48 +01:00
|
|
|
}
|
|
|
|
}
|
2024-01-29 00:43:01 +01:00
|
|
|
|
2024-01-19 15:06:48 +01:00
|
|
|
return true;
|
|
|
|
}
|
2024-01-29 00:43:01 +01:00
|
|
|
|
|
|
|
void handleGameEvent(SDL_Event &event) {
|
|
|
|
if (event.type == SDL_KEYDOWN) {
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2024-01-19 15:06:48 +01:00
|
|
|
};
|