Create GameState
This commit is contained in:
parent
8082c69aff
commit
e5e46a0e65
10 changed files with 80 additions and 85 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
39
lib/Game.cpp
39
lib/Game.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
18
lib/include/GameState.hpp
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace pacman {
|
namespace pacman {
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue