Basic fruits support

Of course, there is no support for levels yet!
This commit is contained in:
Corentin Jabot 2021-09-13 14:47:09 +02:00
parent c95fddc481
commit c495dd9c37
7 changed files with 118 additions and 2 deletions

View file

@ -44,6 +44,8 @@ void Canvas::update(const GameState & gameState) {
renderScore(gameState.score.points); renderScore(gameState.score.points);
renderLives(gameState.score.lives); renderLives(gameState.score.lives);
renderFruits(gameState.fruit, gameState.score.eatenFruits);
renderPacMan(gameState.pacMan); renderPacMan(gameState.pacMan);
render(); render();
@ -99,6 +101,23 @@ void Canvas::renderPacMan(const PacMan & pac_man) {
renderSprite(pacmanSprite, pos); 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) { void Canvas::renderGhost(const Ghost & ghost) {
Sprite sprite = getSprite(ghost.currentSprite()); Sprite sprite = getSprite(ghost.currentSprite());
const auto & pos = ghost.position(); const auto & pos = ghost.position();

53
lib/Fruits.cpp Normal file
View file

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

View file

@ -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 pinky.update(delta, *this); // ghosts know what they want, which is usually pacman's location
inky.update(delta, *this); inky.update(delta, *this);
clyde.update(delta, *this); clyde.update(delta, *this);
fruit.update(delta, *this);
checkCollision(blinky); checkCollision(blinky);
checkCollision(pinky); checkCollision(pinky);
@ -28,12 +29,14 @@ void GameState::step(std::chrono::milliseconds delta) {
checkCollision(clyde); checkCollision(clyde);
eatPellets(); eatPellets();
eatFruit();
} }
void GameState::checkCollision(Ghost & ghost) { void GameState::checkCollision(Ghost & ghost) {
if (isPacManDying() || ghost.isEyes()) if (isPacManDying() || ghost.isEyes())
return; return;
// TODO: hitboxes based collision
if (ghost.positionInGrid() != pacMan.positionInGrid()) if (ghost.positionInGrid() != pacMan.positionInGrid())
return; 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() { void GameState::killPacMan() {
pacMan.die(); pacMan.die();
score.lives--; score.lives--;

View file

@ -37,11 +37,12 @@ private:
void renderGhost(const Ghost & ghost); void renderGhost(const Ghost & ghost);
void renderPellets(const Pellets & pellets); void renderPellets(const Pellets & pellets);
void renderSuperPellets(const SuperPellets & superPellets); void renderSuperPellets(const SuperPellets & superPellets);
void renderSprite(Sprite sprite, Position pos); void renderFruits(const Fruits& fruit, int eatenFruits);
void renderScore(int score); void renderScore(int score);
void renderLives(int lives); void renderLives(int lives);
void renderSprite(Sprite sprite, Position pos);
static Rect viewDimensions(); static Rect viewDimensions();
static sf::Texture loadTexture(std::string_view path); static sf::Texture loadTexture(std::string_view path);
static sf::Font loadFont(std::string_view path); static sf::Font loadFont(std::string_view path);

25
lib/include/Fruits.hpp Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <chrono>
#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

View file

@ -9,6 +9,7 @@
#include "Pinky.hpp" #include "Pinky.hpp"
#include "Score.hpp" #include "Score.hpp"
#include "SuperPellets.hpp" #include "SuperPellets.hpp"
#include "Fruits.hpp"
#include "InputState.hpp" #include "InputState.hpp"
namespace pacman { namespace pacman {
@ -25,6 +26,7 @@ struct GameState {
InputState inputState; InputState inputState;
Pellets pellets; Pellets pellets;
SuperPellets superPellets; SuperPellets superPellets;
Fruits fruit;
Score score; Score score;
std::chrono::milliseconds timeSinceDeath{}; std::chrono::milliseconds timeSinceDeath{};
@ -32,6 +34,7 @@ struct GameState {
void checkCollision(Ghost & ghost); void checkCollision(Ghost & ghost);
void handleDeathAnimation(std::chrono::milliseconds delta); void handleDeathAnimation(std::chrono::milliseconds delta);
void eatPellets(); void eatPellets();
void eatFruit();
void killPacMan(); void killPacMan();
bool isPacManDying() const; bool isPacManDying() const;
}; };

View file

@ -7,6 +7,7 @@ struct Score {
int lives = DEFAULT_LIVES; int lives = DEFAULT_LIVES;
int points = 0; int points = 0;
int eatenPellets = 0; int eatenPellets = 0;
int eatenFruits = 0;
}; };
} // namespace pacman } // namespace pacman