Refactoring Game and GameState. Moving game state update logic into that class. Game is now only event loop.
This commit is contained in:
parent
ee4b216056
commit
55fbb53591
8 changed files with 119 additions and 114 deletions
|
@ -29,7 +29,7 @@ Canvas::Canvas()
|
||||||
game_font = loadFont("retro_font.ttf");
|
game_font = loadFont("retro_font.ttf");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::update(const GameState & gameState, const Score & score) {
|
void Canvas::update(const GameState & gameState) {
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
renderMaze();
|
renderMaze();
|
||||||
|
@ -41,8 +41,8 @@ void Canvas::update(const GameState & gameState, const Score & score) {
|
||||||
renderGhost(gameState.inky);
|
renderGhost(gameState.inky);
|
||||||
renderGhost(gameState.clyde);
|
renderGhost(gameState.clyde);
|
||||||
|
|
||||||
renderScore(score.points);
|
renderScore(gameState.score.points);
|
||||||
renderLives(score.lives);
|
renderLives(gameState.score.lives);
|
||||||
|
|
||||||
renderPacMan(gameState.pacMan);
|
renderPacMan(gameState.pacMan);
|
||||||
|
|
||||||
|
|
106
lib/Game.cpp
106
lib/Game.cpp
|
@ -5,124 +5,32 @@
|
||||||
|
|
||||||
namespace pacman {
|
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() {
|
void Game::run() {
|
||||||
|
|
||||||
const std::chrono::milliseconds delta_time(1000 / 60);
|
const std::chrono::milliseconds delta_time(1000 / 60);
|
||||||
std::chrono::milliseconds accumulator(0);
|
std::chrono::milliseconds accumulator(0);
|
||||||
auto current_time = std::chrono::system_clock::now();
|
auto current_time = std::chrono::system_clock::now();
|
||||||
|
|
||||||
InputState inputState;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto newTime = std::chrono::system_clock::now();
|
auto newTime = std::chrono::system_clock::now();
|
||||||
auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(newTime - current_time);
|
auto frameTime = std::chrono::duration_cast<std::chrono::milliseconds>(newTime - current_time);
|
||||||
|
|
||||||
current_time = newTime;
|
current_time = newTime;
|
||||||
accumulator += frameTime;
|
accumulator += frameTime;
|
||||||
processEvents(inputState);
|
|
||||||
if (inputState.close)
|
processEvents(gameState.inputState);
|
||||||
|
if (gameState.inputState.close)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (accumulator >= delta_time) {
|
while (accumulator >= delta_time) {
|
||||||
step(delta_time, inputState);
|
gameState.step(delta_time);
|
||||||
accumulator -= 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) {
|
void Game::processEvents(InputState & inputState) {
|
||||||
|
|
||||||
auto event = canvas.pollEvent();
|
auto event = canvas.pollEvent();
|
||||||
if (event && event.value().type == sf::Event::Closed) {
|
if (event && event.value().type == sf::Event::Closed) {
|
||||||
inputState.close = true;
|
inputState.close = true;
|
||||||
|
|
89
lib/GameState.cpp
Normal file
89
lib/GameState.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include "GameState.hpp"
|
#include "GameState.hpp"
|
||||||
#include "Position.hpp"
|
#include "Position.hpp"
|
||||||
#include "Score.hpp"
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace pacman {
|
namespace pacman {
|
||||||
|
@ -15,7 +14,7 @@ using Sprite = sf::Sprite;
|
||||||
class Canvas {
|
class Canvas {
|
||||||
public:
|
public:
|
||||||
Canvas();
|
Canvas();
|
||||||
void update(const GameState & gameState, const Score & score);
|
void update(const GameState & gameState);
|
||||||
std::optional<sf::Event> pollEvent();
|
std::optional<sf::Event> pollEvent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -8,22 +8,13 @@ namespace pacman {
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
public:
|
public:
|
||||||
Game();
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Canvas canvas;
|
Canvas canvas;
|
||||||
GameState gameState;
|
GameState gameState;
|
||||||
Score score;
|
|
||||||
std::chrono::milliseconds timeSinceDeath{};
|
|
||||||
|
|
||||||
void step(std::chrono::milliseconds delta, InputState inputState);
|
|
||||||
void eatPellets();
|
|
||||||
void processEvents(InputState & inputState);
|
void processEvents(InputState & inputState);
|
||||||
void checkCollision(Ghost & ghost);
|
|
||||||
void killPacMan();
|
|
||||||
bool pacManDying() const;
|
|
||||||
void handleDeathAnimation(std::chrono::milliseconds delta);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pacman
|
} // namespace pacman
|
||||||
|
|
|
@ -9,17 +9,31 @@
|
||||||
#include "Pinky.hpp"
|
#include "Pinky.hpp"
|
||||||
#include "Score.hpp"
|
#include "Score.hpp"
|
||||||
#include "SuperPellets.hpp"
|
#include "SuperPellets.hpp"
|
||||||
|
#include "InputState.hpp"
|
||||||
|
|
||||||
namespace pacman {
|
namespace pacman {
|
||||||
|
|
||||||
struct GameState {
|
struct GameState {
|
||||||
|
void step(std::chrono::milliseconds delta);
|
||||||
|
|
||||||
Blinky blinky;
|
Blinky blinky;
|
||||||
Pinky pinky;
|
Pinky pinky;
|
||||||
Inky inky;
|
Inky inky;
|
||||||
Clyde clyde;
|
Clyde clyde;
|
||||||
|
|
||||||
PacMan pacMan;
|
PacMan pacMan;
|
||||||
|
InputState inputState;
|
||||||
Pellets pellets;
|
Pellets pellets;
|
||||||
SuperPellets superPellets;
|
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
|
} // namespace pacman
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
namespace pacman {
|
namespace pacman {
|
||||||
|
|
||||||
|
constexpr int DEFAULT_LIVES = 3;
|
||||||
|
|
||||||
struct Score {
|
struct Score {
|
||||||
int lives = 0;
|
int lives = DEFAULT_LIVES;
|
||||||
int points = 0;
|
int points = 0;
|
||||||
int eatenPellets = 0;
|
int eatenPellets = 0;
|
||||||
};
|
};
|
||||||
|
|
2
test/testGame.cpp
Normal file
2
test/testGame.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "PacMan.hpp"
|
||||||
|
#include <gtest/gtest.h>
|
Loading…
Reference in a new issue