Create GameState

This commit is contained in:
Patricia Aas 2021-07-08 16:57:18 +02:00
parent 8082c69aff
commit e5e46a0e65
10 changed files with 80 additions and 85 deletions

View File

@ -8,11 +8,10 @@
namespace pacman { namespace pacman {
Canvas::Canvas() Canvas::Canvas()
: window(sf::VideoMode((viewDimensions().width/2.0), (viewDimensions().height/2.0)), : window(sf::VideoMode((viewDimensions().width / 2.0), (viewDimensions().height / 2.0)),
"Pacman", "Pacman",
sf::Style::Titlebar | sf::Style::Close) sf::Style::Titlebar | sf::Style::Close),
, view(sf::FloatRect(0, 0, viewDimensions().width, viewDimensions().height)) view(sf::FloatRect(0, 0, viewDimensions().width, viewDimensions().height)) {
{
window.setView(view); window.setView(view);
window.setFramerateLimit(60); window.setFramerateLimit(60);
@ -21,30 +20,29 @@ Canvas::Canvas()
// We render the game in view at twice the native resolution, // We render the game in view at twice the native resolution,
// Then project it on a scaled window - on some mac we get the // Then project it on a scaled window - on some mac we get the
// scaling factor of the window to adjust the resolution // scaling factor of the window to adjust the resolution
const auto scale = scaling_factor_for_window(window.getSystemHandle()); const auto scale = scaling_factor_for_window(window.getSystemHandle());
const auto width = viewDimensions().width/2.0 * scale; const auto width = viewDimensions().width / 2.0 * scale;
const auto height = viewDimensions().height/2.0 * scale; const auto height = viewDimensions().height / 2.0 * scale;
window.setSize(sf::Vector2u(width, height)); window.setSize(sf::Vector2u(width, height));
maze_texture = loadTexture("maze.png"); maze_texture = loadTexture("maze.png");
sprites_texture = loadTexture("sprites32.png"); sprites_texture = loadTexture("sprites32.png");
game_font = loadFont("retro_font.ttf"); game_font = loadFont("retro_font.ttf");
} }
void Canvas::update(const Game & game) { void Canvas::update(const GameState & gameState, const Score & score) {
clear(); clear();
renderMaze(); renderMaze();
renderPellets(game.pellets); renderPellets(gameState.pellets);
renderSuperPellets(game.superPellets); renderSuperPellets(gameState.superPellets);
std::apply([&](const auto &... ghost) { (renderGhost(ghost), ...); }, game.ghosts); std::apply([&](const auto &... ghost) { (renderGhost(ghost), ...); }, gameState.ghosts);
renderScore(game.score.points); renderScore(score.points);
renderLives(game.score.lives); renderLives(score.lives);
renderPacMan(game.pacMan); renderPacMan(gameState.pacMan);
render(); render();
} }
@ -107,7 +105,7 @@ void Canvas::renderGhost(const Ghost & ghost) {
void Canvas::renderScore(int score) { void Canvas::renderScore(int score) {
const int x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN); const int x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN);
const int y = (TOP_MARGIN * 2) ; const int y = (TOP_MARGIN * 2);
sf::Text text; sf::Text text;
text.setPosition(x, y); text.setPosition(x, y);
@ -133,8 +131,8 @@ void Canvas::renderLives(int lives) {
} }
Rect Canvas::viewDimensions() { Rect Canvas::viewDimensions() {
const double width = (LEFT_MARGIN + TARGET_MAZE_WIDTH + SCORE_WIDTH); const double width = (LEFT_MARGIN + TARGET_MAZE_WIDTH + SCORE_WIDTH);
const double height = (TOP_MARGIN + TARGET_MAZE_HEIGHT + BOTTOM_MARGIN); const double height = (TOP_MARGIN + TARGET_MAZE_HEIGHT + BOTTOM_MARGIN);
return { 0, 0, int(width), int(height) }; return { 0, 0, int(width), int(height) };
} }
@ -150,7 +148,7 @@ Sprite Canvas::getSprite(GridPosition coordinate) const {
void Canvas::renderSprite(Sprite sprite, Position pos) { void Canvas::renderSprite(Sprite sprite, Position pos) {
pos.x = LEFT_MARGIN + (pos.x * SPRITE_WIDTH); pos.x = LEFT_MARGIN + (pos.x * SPRITE_WIDTH);
pos.y = TOP_MARGIN + (pos.y * SPRITE_HEIGHT); pos.y = TOP_MARGIN + (pos.y * SPRITE_HEIGHT);
sprite.setPosition(pos.x, pos.y); sprite.setPosition(pos.x, pos.y);
window.draw(sprite); window.draw(sprite);
} }

View File

@ -1,4 +1,5 @@
#include "Game.hpp" #include "Game.hpp"
#include "GameState.hpp"
#include <chrono> #include <chrono>
@ -9,11 +10,7 @@ constexpr int NORMAL_PELLET_POINTS = 10;
constexpr int POWER_PELLET_POINTS = 50; constexpr int POWER_PELLET_POINTS = 50;
constexpr int GHOST_POINTS = 200; constexpr int GHOST_POINTS = 200;
Game::Game() Game::Game() {
: pacMan(),
pellets(),
superPellets(),
ghosts(Blinky(), Speedy(), Inky(), Clyde()) {
score.lives = DEFAULT_LIVES; score.lives = DEFAULT_LIVES;
} }
@ -44,13 +41,13 @@ void Game::run() {
accumulator -= delta_time; accumulator -= delta_time;
t += delta_time; t += delta_time;
} }
canvas.update(*this); canvas.update(gameState, score);
} }
} }
void Game::step(std::chrono::milliseconds delta, InputState inputState) { void Game::step(std::chrono::milliseconds delta, InputState inputState) {
pacMan.update(delta, inputState); gameState.pacMan.update(delta, inputState.direction());
if (timeSinceDeath.count() != 0) { if (timeSinceDeath.count() != 0) {
timeSinceDeath += delta; timeSinceDeath += delta;
@ -60,57 +57,57 @@ void Game::step(std::chrono::milliseconds delta, InputState inputState) {
std::apply([&](auto &... ghost) { std::apply([&](auto &... ghost) {
(ghost.reset(), ...); (ghost.reset(), ...);
}, },
ghosts); gameState.ghosts);
pacMan.reset(); gameState.pacMan.reset();
timeSinceDeath = std::chrono::milliseconds(0); timeSinceDeath = std::chrono::milliseconds(0);
} }
if (timeSinceDeath.count()) if (timeSinceDeath.count())
return; return;
if (!pacMan.onTheMove()) if (!gameState.pacMan.hasDirection())
return; return;
std::apply([&](auto &... ghost) { std::apply([&](auto &... ghost) {
(ghost.update(delta), ...); (ghost.update(delta), ...);
(checkCollision(ghost), ...); (checkCollision(ghost), ...);
}, },
ghosts); gameState.ghosts);
eatPellets(); eatPellets();
} }
void Game::checkCollision(Ghost & g) { void Game::checkCollision(Ghost & ghost) {
if (timeSinceDeath.count() || g.isEyes()) if (timeSinceDeath.count() || ghost.isEyes())
return; return;
if (g.positionInGrid() != pacMan.positionInGrid()) if (ghost.positionInGrid() != gameState.pacMan.positionInGrid())
return; return;
if (g.isFrightened()) { if (ghost.isFrightened()) {
g.eat(); ghost.eat();
score.points += GHOST_POINTS; score.points += GHOST_POINTS;
} else { } else {
pacMan.eat(); gameState.pacMan.eat();
score.lives--; score.lives--;
timeSinceDeath = std::chrono::milliseconds(1); timeSinceDeath = std::chrono::milliseconds(1);
} }
} }
void Game::eatPellets() { void Game::eatPellets() {
const auto pos = pacMan.positionInGrid(); const auto pos = gameState.pacMan.positionInGrid();
if (pellets.eatPelletAtPosition(pos)) { if (gameState.pellets.eatPelletAtPosition(pos)) {
score.eatenPellets++; score.eatenPellets++;
score.points += NORMAL_PELLET_POINTS; score.points += NORMAL_PELLET_POINTS;
} }
if (superPellets.eatPelletAtPosition(pos)) { if (gameState.superPellets.eatPelletAtPosition(pos)) {
score.eatenPellets++; score.eatenPellets++;
score.points += POWER_PELLET_POINTS; score.points += POWER_PELLET_POINTS;
std::apply([&](auto &... ghost) { std::apply([&](auto &... ghost) {
(ghost.frighten(), ...); (ghost.frighten(), ...);
}, },
ghosts); gameState.ghosts);
} }
} }

View File

@ -31,29 +31,19 @@ void PacMan::reset() {
pos = pacman::Board::initialPacManPosition(); pos = pacman::Board::initialPacManPosition();
} }
void PacMan::update(std::chrono::milliseconds time_delta, InputState state) { void PacMan::update(std::chrono::milliseconds time_delta, Direction input_direction) {
if (eaten) { if (eaten) {
updateAnimationPosition(time_delta, false); updateAnimationPosition(time_delta, false);
return; return;
} }
if (input_direction != Direction::NONE)
desired_direction = input_direction;
const auto old = pos; const auto old = pos;
setDirection(state);
updateMazePosition(time_delta); updateMazePosition(time_delta);
const bool paused = pos == old; const bool paused = pos == old;
updateAnimationPosition(time_delta, paused); updateAnimationPosition(time_delta, paused);
} }
void PacMan::setDirection(const InputState & state) {
if (state.left)
desired_direction = Direction::LEFT;
else if (state.right)
desired_direction = Direction::RIGHT;
else if (state.up)
desired_direction = Direction::UP;
else if (state.down)
desired_direction = Direction::DOWN;
}
void PacMan::updateAnimationPosition(std::chrono::milliseconds time_delta, bool paused) { void PacMan::updateAnimationPosition(std::chrono::milliseconds time_delta, bool paused) {
if (paused) { if (paused) {
pacManAnimation.pause(); pacManAnimation.pause();

View File

@ -1,31 +1,26 @@
#pragma once #pragma once
#include "GameState.hpp"
#include "Position.hpp" #include "Position.hpp"
#include "Score.hpp" #include "Score.hpp"
#include <optional> #include <optional>
namespace pacman { namespace pacman {
class Game;
class Ghost;
class PacMan;
class Pellets;
class SuperPellets;
class Canvas { class Canvas {
public: public:
Canvas(); Canvas();
void update(const Game & game); void update(const GameState & gameState, const Score & score);
std::optional<sf::Event> pollEvent(); std::optional<sf::Event> pollEvent();
private: private:
static constexpr uint16_t LEFT_MARGIN = 40 * 2; static constexpr uint16_t LEFT_MARGIN = 40 * 2;
static constexpr uint16_t TOP_MARGIN = 40 * 2; static constexpr uint16_t TOP_MARGIN = 40 * 2;
static constexpr uint16_t BOTTOM_MARGIN = 40 * 2; static constexpr uint16_t BOTTOM_MARGIN = 40 * 2;
static constexpr uint16_t MAZE_WIDTH = 448; static constexpr uint16_t MAZE_WIDTH = 448;
static constexpr uint16_t MAZE_HEIGHT = 496; static constexpr uint16_t MAZE_HEIGHT = 496;
static constexpr uint16_t MAZE_SCALE_UP = 2; static constexpr uint16_t MAZE_SCALE_UP = 2;
static constexpr uint16_t TARGET_MAZE_WIDTH = 448 * MAZE_SCALE_UP; static constexpr uint16_t TARGET_MAZE_WIDTH = 448 * MAZE_SCALE_UP;
static constexpr uint16_t TARGET_MAZE_HEIGHT = 496 * MAZE_SCALE_UP; static constexpr uint16_t TARGET_MAZE_HEIGHT = 496 * MAZE_SCALE_UP;
static constexpr uint16_t SCORE_WIDTH = 200 * 2; static constexpr uint16_t SCORE_WIDTH = 200 * 2;
static constexpr uint16_t SPRITE_WIDTH = 32; static constexpr uint16_t SPRITE_WIDTH = 32;
@ -54,7 +49,6 @@ private:
sf::Texture maze_texture; sf::Texture maze_texture;
sf::Texture sprites_texture; sf::Texture sprites_texture;
sf::Font game_font; sf::Font game_font;
}; };
} // namespace pacman } // namespace pacman

View File

@ -1,38 +1,26 @@
#pragma once #pragma once
#include "Board.hpp"
#include "Canvas.hpp" #include "Canvas.hpp"
#include "Ghost.hpp" #include "GameState.hpp"
#include "PacMan.hpp" #include "InputState.hpp"
#include "Pellets.hpp"
#include "Score.hpp"
#include "SuperPellets.hpp"
namespace pacman { namespace pacman {
class InputState;
class Game { class Game {
public: public:
Game(); Game();
void run(); void run();
private: private:
friend class Canvas;
Canvas canvas; Canvas canvas;
Board board; GameState gameState;
PacMan pacMan;
Pellets pellets;
SuperPellets superPellets;
std::tuple<Blinky, Speedy, Inky, Clyde> ghosts;
Score score; Score score;
std::chrono::milliseconds timeSinceDeath{}; std::chrono::milliseconds timeSinceDeath{};
void step(std::chrono::milliseconds delta, InputState inputState); void step(std::chrono::milliseconds delta, InputState inputState);
void eatPellets(); void eatPellets();
void processEvents(InputState & inputState); void processEvents(InputState & inputState);
void checkCollision(Ghost & g); void checkCollision(Ghost & ghost);
[[nodiscard]] static auto now(); [[nodiscard]] static auto now();
}; };

18
lib/include/GameState.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "Ghost.hpp"
#include "PacMan.hpp"
#include "Pellets.hpp"
#include "Score.hpp"
#include "SuperPellets.hpp"
namespace pacman {
struct GameState {
std::tuple<Blinky, Speedy, Inky, Clyde> ghosts;
PacMan pacMan;
Pellets pellets;
SuperPellets superPellets;
};
} // namespace pacman

View File

@ -9,6 +9,19 @@ public:
bool down = false; bool down = false;
bool left = false; bool left = false;
bool right = false; bool right = false;
[[nodiscard]] Direction direction() const {
if (left)
return Direction::LEFT;
else if (right)
return Direction::RIGHT;
else if (up)
return Direction::UP;
else if (down)
return Direction::DOWN;
else
return Direction::NONE;
}
}; };
} // namespace pacman } // namespace pacman

View File

@ -21,11 +21,11 @@ public:
[[nodiscard]] GridPosition positionInGrid() const; [[nodiscard]] GridPosition positionInGrid() const;
void update(std::chrono::milliseconds time_delta, InputState state); void update(std::chrono::milliseconds time_delta, Direction input_direction);
void eat(); void eat();
void reset(); void reset();
[[nodiscard]] bool onTheMove() const { [[nodiscard]] bool hasDirection() const {
return direction != Direction::NONE; return direction != Direction::NONE;
} }
@ -36,8 +36,6 @@ private:
PacManAnimation pacManAnimation; PacManAnimation pacManAnimation;
bool eaten = false; bool eaten = false;
void setDirection(const InputState & state);
void updateAnimationPosition(std::chrono::milliseconds time_delta, bool paused); void updateAnimationPosition(std::chrono::milliseconds time_delta, bool paused);
void updateMazePosition(std::chrono::milliseconds time_delta); void updateMazePosition(std::chrono::milliseconds time_delta);
}; };

View File

@ -3,7 +3,6 @@
#include "Atlas.hpp" #include "Atlas.hpp"
#include "Board.hpp" #include "Board.hpp"
#include "Direction.hpp" #include "Direction.hpp"
#include "InputState.hpp"
#include "Position.hpp" #include "Position.hpp"
#include <chrono> #include <chrono>

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <cmath>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <cmath>
namespace pacman { namespace pacman {