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

View File

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

View File

@ -31,29 +31,19 @@ void PacMan::reset() {
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) {
updateAnimationPosition(time_delta, false);
return;
}
if (input_direction != Direction::NONE)
desired_direction = input_direction;
const auto old = pos;
setDirection(state);
updateMazePosition(time_delta);
const bool paused = pos == old;
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) {
if (paused) {
pacManAnimation.pause();

View File

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

View File

@ -1,38 +1,26 @@
#pragma once
#include "Board.hpp"
#include "Canvas.hpp"
#include "Ghost.hpp"
#include "PacMan.hpp"
#include "Pellets.hpp"
#include "Score.hpp"
#include "SuperPellets.hpp"
#include "GameState.hpp"
#include "InputState.hpp"
namespace pacman {
class InputState;
class Game {
public:
Game();
void run();
private:
friend class Canvas;
Canvas canvas;
Board board;
PacMan pacMan;
Pellets pellets;
SuperPellets superPellets;
std::tuple<Blinky, Speedy, Inky, Clyde> ghosts;
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 & g);
void checkCollision(Ghost & ghost);
[[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 left = 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

View File

@ -21,11 +21,11 @@ public:
[[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 reset();
[[nodiscard]] bool onTheMove() const {
[[nodiscard]] bool hasDirection() const {
return direction != Direction::NONE;
}
@ -36,8 +36,6 @@ private:
PacManAnimation pacManAnimation;
bool eaten = false;
void setDirection(const InputState & state);
void updateAnimationPosition(std::chrono::milliseconds time_delta, bool paused);
void updateMazePosition(std::chrono::milliseconds time_delta);
};

View File

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

View File

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