diff --git a/lib/Canvas.cpp b/lib/Canvas.cpp index 28dfea3..4c81676 100644 --- a/lib/Canvas.cpp +++ b/lib/Canvas.cpp @@ -107,13 +107,15 @@ void Canvas::renderFruits(const Fruits & fruit, int eatenFruits) { const auto & pos = fruit.position(); renderSprite(sprite, pos); } + const auto x = static_cast(LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN); const auto y = static_cast((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 }; + const auto sprite_position = float(i) * SPRITE_WIDTH * 1.5f; + const sf::Vector2f pos{ x + sprite_position, y }; sprite.setPosition(pos.x, pos.y); + window.draw(sprite); } } diff --git a/lib/Fruits.cpp b/lib/Fruits.cpp index e022da7..b47b700 100644 --- a/lib/Fruits.cpp +++ b/lib/Fruits.cpp @@ -4,50 +4,50 @@ namespace pacman { void Fruits::update(std::chrono::milliseconds time_delta, const GameState & gameState) { - if(visible) { - time_visible += time_delta; - } + 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; - } + if (time_visible > std::chrono::seconds(9)) { + hide(); + } else if ((index == 0 && gameState.score.eatenPellets >= 70) || (index == 1 && gameState.score.eatenPellets >= 170)) { + // We show the fruit twice, once at 70 pellets and once at 170 + visible = true; + } } GridPosition Fruits::currentSprite() const { - // That's the cherry - return {3, 8}; + // That's the cherry + return { 3, 8 }; } Position Fruits::position() const { - // under the pen - return {13.5, 17}; + // under the pen + return { 13.5, 17 }; } bool Fruits::isVisible() const { - return visible; + return visible; } int Fruits::value() const { - // The cherry is worth 100 - return 100; + // The cherry is worth 100 + return 100; } int Fruits::eat() { - hide(); - return value(); + if (!isVisible()) { + return 0; + } + + hide(); + return value(); } void Fruits::hide() { - index++; - time_visible = std::chrono::seconds{0}; - visible = false; + index++; + time_visible = std::chrono::seconds{ 0 }; + visible = false; } - -} +} // namespace pacman diff --git a/lib/include/Fruits.hpp b/lib/include/Fruits.hpp index 9bd96a4..d89bc53 100644 --- a/lib/include/Fruits.hpp +++ b/lib/include/Fruits.hpp @@ -9,17 +9,20 @@ struct 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 }; + + void hide(); }; } // namespace pacman diff --git a/test/testFruits.cpp b/test/testFruits.cpp new file mode 100644 index 0000000..f0832e7 --- /dev/null +++ b/test/testFruits.cpp @@ -0,0 +1,77 @@ +#include "Fruits.hpp" +#include "GameState.hpp" +#include + +TEST_CASE("Fruit default initialization", "[fruits]") { + pacman::Fruits fruit; + REQUIRE_FALSE(fruit.isVisible()); + REQUIRE(fruit.value() == 100); + REQUIRE(fruit.currentSprite().x == 3); + REQUIRE(fruit.currentSprite().y == 8); + REQUIRE(fruit.position().x == Approx(13.5)); + REQUIRE(fruit.position().y == Approx(17)); +} + +TEST_CASE("Fruit Visibility", "[fruits]") { + pacman::GameState gameState; + REQUIRE_FALSE(gameState.fruit.isVisible()); + + SECTION("9 seconds but no pellets eaten") { + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + } + + SECTION("9 seconds and 70 pellets eaten") { + // "Eat 70 pellets", do an update and check the state + gameState.score.eatenPellets = 70; + gameState.fruit.update(std::chrono::milliseconds(1), gameState); + REQUIRE(gameState.fruit.isVisible()); + + // Wait more than 9 seconds and then check the state again + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + } + + SECTION("70 and 170 pellets eaten") { + // "Eat 70 pellets", do an update and check the state + gameState.score.eatenPellets = 70; + gameState.fruit.update(std::chrono::milliseconds(1), gameState); + REQUIRE(gameState.fruit.isVisible()); + + // Wait more than 9 seconds and then check the state again + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + + // "Eat 170 pellets", do an update and check the state + gameState.score.eatenPellets = 170; + gameState.fruit.update(std::chrono::milliseconds(1), gameState); + REQUIRE(gameState.fruit.isVisible()); + + // Wait more than 9 seconds and then check the state again + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + + // We should never get a visible state again, since we only show 2 fruits + gameState.score.eatenPellets = 1000; + gameState.fruit.update(std::chrono::milliseconds(1), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + + // Wait more than 9 seconds and then check the state again + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + } + + SECTION("Eating a fruit") { + REQUIRE(gameState.fruit.eat() == 0); + + gameState.score.eatenPellets = 70; + gameState.fruit.update(std::chrono::milliseconds(1), gameState); + REQUIRE(gameState.fruit.isVisible()); + REQUIRE(gameState.fruit.eat() == gameState.fruit.value()); + + // Wait more than 9 seconds and then check the state again + gameState.fruit.update(std::chrono::milliseconds(9001), gameState); + REQUIRE_FALSE(gameState.fruit.isVisible()); + REQUIRE(gameState.fruit.eat() == 0); + } +} \ No newline at end of file