Adding unit tests for fruits. Also some minor cleanup.

This commit is contained in:
Ólafur Waage 2021-09-15 14:40:07 +02:00
parent 0923351045
commit cd86d91310
4 changed files with 111 additions and 29 deletions

View File

@ -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<size_t>(LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN);
const auto y = static_cast<size_t>((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);
}
}

View File

@ -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

View File

@ -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

77
test/testFruits.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "Fruits.hpp"
#include "GameState.hpp"
#include <catch2/catch.hpp>
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);
}
}