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);
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();

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

View File

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

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

View File

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