From 55fbb53591f1470313364e86ef083fab2d6d6044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20Waage?= Date: Tue, 7 Sep 2021 16:00:19 +0200 Subject: [PATCH] Refactoring Game and GameState. Moving game state update logic into that class. Game is now only event loop. --- lib/Canvas.cpp | 6 +-- lib/Game.cpp | 106 +++----------------------------------- lib/GameState.cpp | 89 ++++++++++++++++++++++++++++++++ lib/include/Canvas.hpp | 3 +- lib/include/Game.hpp | 9 ---- lib/include/GameState.hpp | 14 +++++ lib/include/Score.hpp | 4 +- test/testGame.cpp | 2 + 8 files changed, 119 insertions(+), 114 deletions(-) create mode 100644 lib/GameState.cpp create mode 100644 test/testGame.cpp diff --git a/lib/Canvas.cpp b/lib/Canvas.cpp index 431c371..b925a48 100644 --- a/lib/Canvas.cpp +++ b/lib/Canvas.cpp @@ -29,7 +29,7 @@ Canvas::Canvas() game_font = loadFont("retro_font.ttf"); } -void Canvas::update(const GameState & gameState, const Score & score) { +void Canvas::update(const GameState & gameState) { clear(); renderMaze(); @@ -41,8 +41,8 @@ void Canvas::update(const GameState & gameState, const Score & score) { renderGhost(gameState.inky); renderGhost(gameState.clyde); - renderScore(score.points); - renderLives(score.lives); + renderScore(gameState.score.points); + renderLives(gameState.score.lives); renderPacMan(gameState.pacMan); diff --git a/lib/Game.cpp b/lib/Game.cpp index 7d085ca..02a9d74 100644 --- a/lib/Game.cpp +++ b/lib/Game.cpp @@ -5,124 +5,32 @@ namespace pacman { -constexpr int DEFAULT_LIVES = 3; -constexpr int NORMAL_PELLET_POINTS = 10; -constexpr int POWER_PELLET_POINTS = 50; -constexpr int GHOST_POINTS = 200; - -Game::Game() { - score.lives = DEFAULT_LIVES; -} - void Game::run() { - const std::chrono::milliseconds delta_time(1000 / 60); std::chrono::milliseconds accumulator(0); auto current_time = std::chrono::system_clock::now(); - InputState inputState; - while (true) { auto newTime = std::chrono::system_clock::now(); auto frameTime = std::chrono::duration_cast(newTime - current_time); + current_time = newTime; accumulator += frameTime; - processEvents(inputState); - if (inputState.close) + + processEvents(gameState.inputState); + if (gameState.inputState.close) return; + while (accumulator >= delta_time) { - step(delta_time, inputState); + gameState.step(delta_time); accumulator -= delta_time; } - canvas.update(gameState, score); - } -} - -void Game::killPacMan() { - gameState.pacMan.die(); - score.lives--; - timeSinceDeath = std::chrono::milliseconds(1); -} - -bool Game::pacManDying() const { - return timeSinceDeath.count() != 0; -} - -void Game::handleDeathAnimation(std::chrono::milliseconds delta) { - timeSinceDeath += delta; - - if (timeSinceDeath.count() > 1000) { - gameState.blinky.reset(); - gameState.pinky.reset(); - gameState.inky.reset(); - gameState.clyde.reset(); - gameState.pacMan.reset(); - timeSinceDeath = std::chrono::milliseconds(0); - } -} - -void Game::step(std::chrono::milliseconds delta, InputState inputState) { - - gameState.pacMan.update(delta, inputState.direction()); - - if (pacManDying()) { - handleDeathAnimation(delta); - return; - } - - if (!gameState.pacMan.hasDirection()) - return; - - gameState.blinky.update(delta, gameState); - gameState.pinky.update(delta, gameState); - gameState.inky.update(delta, gameState); - gameState.clyde.update(delta, gameState); - - checkCollision(gameState.blinky); - checkCollision(gameState.pinky); - checkCollision(gameState.inky); - checkCollision(gameState.clyde); - - - eatPellets(); -} - -void Game::checkCollision(Ghost & ghost) { - if (pacManDying() || ghost.isEyes()) - return; - - if (ghost.positionInGrid() != gameState.pacMan.positionInGrid()) - return; - - if (ghost.isFrightened()) { - ghost.die(); - score.points += GHOST_POINTS; - } else { - killPacMan(); - } -} - -void Game::eatPellets() { - const auto pos = gameState.pacMan.positionInGrid(); - if (gameState.pellets.eatPelletAtPosition(pos)) { - score.eatenPellets++; - score.points += NORMAL_PELLET_POINTS; - } - - if (gameState.superPellets.eatPelletAtPosition(pos)) { - score.eatenPellets++; - score.points += POWER_PELLET_POINTS; - - gameState.blinky.frighten(); - gameState.pinky.frighten(); - gameState.inky.frighten(); - gameState.clyde.frighten(); + canvas.update(gameState); } } void Game::processEvents(InputState & inputState) { - auto event = canvas.pollEvent(); if (event && event.value().type == sf::Event::Closed) { inputState.close = true; diff --git a/lib/GameState.cpp b/lib/GameState.cpp new file mode 100644 index 0000000..ae5d930 --- /dev/null +++ b/lib/GameState.cpp @@ -0,0 +1,89 @@ +#include "GameState.hpp" + +namespace pacman { + +constexpr int GHOST_POINTS = 200; +constexpr int NORMAL_PELLET_POINTS = 10; +constexpr int POWER_PELLET_POINTS = 50; + +void GameState::step(std::chrono::milliseconds delta) { + pacMan.update(delta, inputState.direction()); + + if (isPacManDying()) { + handleDeathAnimation(delta); + return; + } + + if (!pacMan.hasDirection()) + return; + + blinky.update(delta, *this); // waage: urgh, I wanna remove this + pinky.update(delta, *this); // ghosts know what they want, which is usually pacman's location + inky.update(delta, *this); + clyde.update(delta, *this); + + checkCollision(blinky); + checkCollision(pinky); + checkCollision(inky); + checkCollision(clyde); + + eatPellets(); +} + +void GameState::checkCollision(Ghost & ghost) { + if (isPacManDying() || ghost.isEyes()) + return; + + if (ghost.positionInGrid() != pacMan.positionInGrid()) + return; + + if (ghost.isFrightened()) { + ghost.die(); + score.points += GHOST_POINTS; + } else { + killPacMan(); + } +} + +void GameState::handleDeathAnimation(std::chrono::milliseconds delta) { + timeSinceDeath += delta; + + if (timeSinceDeath.count() > 1000) { + blinky.reset(); + pinky.reset(); + inky.reset(); + clyde.reset(); + pacMan.reset(); + timeSinceDeath = std::chrono::milliseconds(0); + } +} + +void GameState::eatPellets() { + const auto pos = pacMan.positionInGrid(); + if (pellets.eatPelletAtPosition(pos)) { + score.eatenPellets++; + score.points += NORMAL_PELLET_POINTS; + } + + if (superPellets.eatPelletAtPosition(pos)) { + score.eatenPellets++; + score.points += POWER_PELLET_POINTS; + + blinky.frighten(); + pinky.frighten(); + inky.frighten(); + clyde.frighten(); + } +} + +void GameState::killPacMan() { + pacMan.die(); + score.lives--; + timeSinceDeath = std::chrono::milliseconds(1); +} + +bool GameState::isPacManDying() const { + return timeSinceDeath.count() != 0; +} + +} \ No newline at end of file diff --git a/lib/include/Canvas.hpp b/lib/include/Canvas.hpp index eb315b2..3dc529e 100644 --- a/lib/include/Canvas.hpp +++ b/lib/include/Canvas.hpp @@ -4,7 +4,6 @@ #include "GameState.hpp" #include "Position.hpp" -#include "Score.hpp" #include namespace pacman { @@ -15,7 +14,7 @@ using Sprite = sf::Sprite; class Canvas { public: Canvas(); - void update(const GameState & gameState, const Score & score); + void update(const GameState & gameState); std::optional pollEvent(); private: diff --git a/lib/include/Game.hpp b/lib/include/Game.hpp index db1e224..c6b9b78 100644 --- a/lib/include/Game.hpp +++ b/lib/include/Game.hpp @@ -8,22 +8,13 @@ namespace pacman { class Game { public: - Game(); void run(); private: Canvas canvas; GameState gameState; - Score score; - std::chrono::milliseconds timeSinceDeath{}; - void step(std::chrono::milliseconds delta, InputState inputState); - void eatPellets(); void processEvents(InputState & inputState); - void checkCollision(Ghost & ghost); - void killPacMan(); - bool pacManDying() const; - void handleDeathAnimation(std::chrono::milliseconds delta); }; } // namespace pacman diff --git a/lib/include/GameState.hpp b/lib/include/GameState.hpp index 8a1aa88..794ca48 100644 --- a/lib/include/GameState.hpp +++ b/lib/include/GameState.hpp @@ -9,17 +9,31 @@ #include "Pinky.hpp" #include "Score.hpp" #include "SuperPellets.hpp" +#include "InputState.hpp" namespace pacman { struct GameState { + void step(std::chrono::milliseconds delta); + Blinky blinky; Pinky pinky; Inky inky; Clyde clyde; + PacMan pacMan; + InputState inputState; Pellets pellets; SuperPellets superPellets; + + Score score; + std::chrono::milliseconds timeSinceDeath{}; + + void checkCollision(Ghost & ghost); + void handleDeathAnimation(std::chrono::milliseconds delta); + void eatPellets(); + void killPacMan(); + bool isPacManDying() const; }; } // namespace pacman diff --git a/lib/include/Score.hpp b/lib/include/Score.hpp index 1978fa5..3ef475e 100644 --- a/lib/include/Score.hpp +++ b/lib/include/Score.hpp @@ -1,8 +1,10 @@ #pragma once namespace pacman { +constexpr int DEFAULT_LIVES = 3; + struct Score { - int lives = 0; + int lives = DEFAULT_LIVES; int points = 0; int eatenPellets = 0; }; diff --git a/test/testGame.cpp b/test/testGame.cpp new file mode 100644 index 0000000..74c51ca --- /dev/null +++ b/test/testGame.cpp @@ -0,0 +1,2 @@ +#include "PacMan.hpp" +#include