From c495dd9c37ad2d11538624d7b1a8aec8deac8edd Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Mon, 13 Sep 2021 14:47:09 +0200 Subject: [PATCH] Basic fruits support Of course, there is no support for levels yet! --- lib/Canvas.cpp | 19 ++++++++++++++ lib/Fruits.cpp | 53 +++++++++++++++++++++++++++++++++++++++ lib/GameState.cpp | 16 +++++++++++- lib/include/Canvas.hpp | 3 ++- lib/include/Fruits.hpp | 25 ++++++++++++++++++ lib/include/GameState.hpp | 3 +++ lib/include/Score.hpp | 1 + 7 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 lib/Fruits.cpp create mode 100644 lib/include/Fruits.hpp diff --git a/lib/Canvas.cpp b/lib/Canvas.cpp index a58b46c..d87dac4 100644 --- a/lib/Canvas.cpp +++ b/lib/Canvas.cpp @@ -44,6 +44,8 @@ void Canvas::update(const GameState & gameState) { renderScore(gameState.score.points); renderLives(gameState.score.lives); + renderFruits(gameState.fruit, gameState.score.eatenFruits); + renderPacMan(gameState.pacMan); render(); @@ -99,6 +101,23 @@ void Canvas::renderPacMan(const PacMan & pac_man) { renderSprite(pacmanSprite, pos); } +void Canvas::renderFruits(const Fruits& fruit, int eatenFruits) { + Sprite sprite = getSprite(fruit.currentSprite()); + if(fruit.isVisible()) { + const auto & pos = fruit.position(); + renderSprite(sprite, pos); + } + const size_t x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN); + const size_t y = (TARGET_MAZE_HEIGHT / 3.0) * 2; + + for (auto i = 0; i < eatenFruits + 1; i++) { + auto sprite_position = float(i) * SPRITE_WIDTH * 1.5f; + sf::Vector2f pos{ x + sprite_position, y }; + sprite.setPosition(pos.x, pos.y); + window.draw(sprite); + } +} + void Canvas::renderGhost(const Ghost & ghost) { Sprite sprite = getSprite(ghost.currentSprite()); const auto & pos = ghost.position(); diff --git a/lib/Fruits.cpp b/lib/Fruits.cpp new file mode 100644 index 0000000..e022da7 --- /dev/null +++ b/lib/Fruits.cpp @@ -0,0 +1,53 @@ +#include "Fruits.hpp" +#include "GameState.hpp" + +namespace pacman { + +void Fruits::update(std::chrono::milliseconds time_delta, const GameState & gameState) { + if(visible) { + time_visible += time_delta; + } + + if(time_visible > std::chrono::seconds(9)) { + hide(); + } + + // Two times the same fruit for each level, after 70 and 170 pellets eaten + else if ((index == 0 && gameState.score.eatenPellets >= 70) + || (index == 1 && gameState.score.eatenPellets >= 170)) { + visible = true; + } +} + +GridPosition Fruits::currentSprite() const { + // That's the cherry + return {3, 8}; +} + +Position Fruits::position() const { + // under the pen + return {13.5, 17}; +} + +bool Fruits::isVisible() const { + return visible; +} + +int Fruits::value() const { + // The cherry is worth 100 + return 100; +} + +int Fruits::eat() { + hide(); + return value(); +} + +void Fruits::hide() { + index++; + time_visible = std::chrono::seconds{0}; + visible = false; +} + + +} diff --git a/lib/GameState.cpp b/lib/GameState.cpp index ae5d930..8610a44 100644 --- a/lib/GameState.cpp +++ b/lib/GameState.cpp @@ -21,6 +21,7 @@ void GameState::step(std::chrono::milliseconds delta) { pinky.update(delta, *this); // ghosts know what they want, which is usually pacman's location inky.update(delta, *this); clyde.update(delta, *this); + fruit.update(delta, *this); checkCollision(blinky); checkCollision(pinky); @@ -28,12 +29,14 @@ void GameState::step(std::chrono::milliseconds delta) { checkCollision(clyde); eatPellets(); + eatFruit(); } void GameState::checkCollision(Ghost & ghost) { if (isPacManDying() || ghost.isEyes()) return; + // TODO: hitboxes based collision if (ghost.positionInGrid() != pacMan.positionInGrid()) return; @@ -76,6 +79,17 @@ void GameState::eatPellets() { } } +void GameState::eatFruit() { + const auto pos = pacMan.positionInGrid(); + const auto fruitpos = positionToGridPosition(fruit.position()); + + // TODO: hitboxes based collision + if(fruit.isVisible() && pos == fruitpos) { + score.points += fruit.eat(); + score.eatenFruits++; + } +} + void GameState::killPacMan() { pacMan.die(); score.lives--; @@ -86,4 +100,4 @@ 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 3dc529e..2d24672 100644 --- a/lib/include/Canvas.hpp +++ b/lib/include/Canvas.hpp @@ -37,11 +37,12 @@ private: void renderGhost(const Ghost & ghost); void renderPellets(const Pellets & pellets); void renderSuperPellets(const SuperPellets & superPellets); - void renderSprite(Sprite sprite, Position pos); + void renderFruits(const Fruits& fruit, int eatenFruits); void renderScore(int score); void renderLives(int lives); + void renderSprite(Sprite sprite, Position pos); static Rect viewDimensions(); static sf::Texture loadTexture(std::string_view path); static sf::Font loadFont(std::string_view path); diff --git a/lib/include/Fruits.hpp b/lib/include/Fruits.hpp new file mode 100644 index 0000000..53afcc0 --- /dev/null +++ b/lib/include/Fruits.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include "Position.hpp" + +namespace pacman { + +class GameState; +class Fruits { + +public: + void update(std::chrono::milliseconds time_delta, const GameState & gameState); + GridPosition currentSprite() const; + Position position() const; + bool isVisible() const; + int value() const; + int eat(); + +private: + void hide(); + bool visible = false; + int index = 0; + std::chrono::milliseconds time_visible{0}; +}; + +} // namespace pacman diff --git a/lib/include/GameState.hpp b/lib/include/GameState.hpp index 794ca48..7a74779 100644 --- a/lib/include/GameState.hpp +++ b/lib/include/GameState.hpp @@ -9,6 +9,7 @@ #include "Pinky.hpp" #include "Score.hpp" #include "SuperPellets.hpp" +#include "Fruits.hpp" #include "InputState.hpp" namespace pacman { @@ -25,6 +26,7 @@ struct GameState { InputState inputState; Pellets pellets; SuperPellets superPellets; + Fruits fruit; Score score; std::chrono::milliseconds timeSinceDeath{}; @@ -32,6 +34,7 @@ struct GameState { void checkCollision(Ghost & ghost); void handleDeathAnimation(std::chrono::milliseconds delta); void eatPellets(); + void eatFruit(); void killPacMan(); bool isPacManDying() const; }; diff --git a/lib/include/Score.hpp b/lib/include/Score.hpp index 3ef475e..dc7f5ce 100644 --- a/lib/include/Score.hpp +++ b/lib/include/Score.hpp @@ -7,6 +7,7 @@ struct Score { int lives = DEFAULT_LIVES; int points = 0; int eatenPellets = 0; + int eatenFruits = 0; }; } // namespace pacman