pacman/lib/Canvas.cpp

180 lines
5.1 KiB
C++
Raw Normal View History

#include "Canvas.hpp"
2021-07-08 08:17:05 +00:00
#include "Scaling.hpp"
#include <fmt/format.h>
#include <string>
#include <vector>
2021-07-05 12:10:01 +00:00
namespace pacman {
Canvas::Canvas()
2021-08-02 13:28:07 +00:00
: window(sf::VideoMode((viewDimensions().width / 2), (viewDimensions().height / 2)),
2021-07-02 12:47:33 +00:00
"Pacman",
2021-07-08 14:57:18 +00:00
sf::Style::Titlebar | sf::Style::Close),
2021-08-02 13:28:07 +00:00
view(sf::FloatRect(0, 0, float(viewDimensions().width), float(viewDimensions().height))) {
window.setView(view);
window.setFramerateLimit(60);
window.setVerticalSyncEnabled(true);
// We render the game in view at twice the native resolution,
// Then project it on a scaled window - on some mac we get the
// scaling factor of the window to adjust the resolution
2021-07-08 14:57:18 +00:00
const auto scale = scaling_factor_for_window(window.getSystemHandle());
2021-08-02 13:28:07 +00:00
const auto width = (viewDimensions().width / 2) * scale;
const auto height = (viewDimensions().height / 2) * scale;
window.setSize(sf::Vector2u(unsigned(width), unsigned(height)));
maze_texture = loadTexture("maze.png");
sprites_texture = loadTexture("sprites32.png");
2021-07-06 18:48:29 +00:00
game_font = loadFont("retro_font.ttf");
}
void Canvas::update(const GameState & gameState) {
clear();
renderMaze();
2021-07-08 14:57:18 +00:00
renderPellets(gameState.pellets);
renderSuperPellets(gameState.superPellets);
2021-06-24 11:32:52 +00:00
2021-07-15 07:14:25 +00:00
renderGhost(gameState.blinky);
2021-07-16 07:35:32 +00:00
renderGhost(gameState.pinky);
2021-07-15 07:14:25 +00:00
renderGhost(gameState.inky);
renderGhost(gameState.clyde);
2021-06-24 11:32:52 +00:00
renderScore(gameState.score.points);
renderLives(gameState.score.lives);
2021-07-08 14:57:18 +00:00
renderPacMan(gameState.pacMan);
2021-06-28 10:42:21 +00:00
render();
}
void Canvas::clear() {
window.clear(sf::Color::Black);
}
void Canvas::render() {
window.display();
}
std::optional<sf::Event> Canvas::pollEvent() {
2021-06-22 08:28:23 +00:00
sf::Event event{};
if (window.pollEvent(event))
return event;
return std::nullopt;
}
void Canvas::renderMaze() {
2021-07-06 20:16:11 +00:00
Sprite maze;
maze.setTexture(maze_texture);
maze.setTextureRect(sf::IntRect{
0,
0,
MAZE_WIDTH,
MAZE_HEIGHT });
maze.setScale(MAZE_SCALE_UP, MAZE_SCALE_UP);
maze.setPosition(LEFT_MARGIN, TOP_MARGIN);
window.draw(maze);
}
void Canvas::renderPellets(const Pellets & pellets) {
Sprite pellet = getSprite(pellets.currentSprite());
2021-07-05 09:46:49 +00:00
std::vector<GridPosition> pelletPositions = pellets.currentPositions();
for (const auto & pos : pelletPositions) {
renderSprite(pellet, gridPositionToPosition(pos));
}
}
void Canvas::renderSuperPellets(const SuperPellets & superPellets) {
Sprite pellet = getSprite(superPellets.currentSprite());
2021-07-05 09:46:49 +00:00
std::vector<GridPosition> superPelletPositions = superPellets.currentPositions();
for (const auto & pos : superPelletPositions) {
renderSprite(pellet, gridPositionToPosition(pos));
}
}
void Canvas::renderPacMan(const PacMan & pac_man) {
Sprite pacmanSprite = getSprite(pac_man.currentSprite());
const auto & pos = pac_man.position();
2021-06-22 10:00:29 +00:00
renderSprite(pacmanSprite, pos);
}
2021-06-24 11:32:52 +00:00
void Canvas::renderGhost(const Ghost & ghost) {
Sprite sprite = getSprite(ghost.currentSprite());
const auto & pos = ghost.position();
renderSprite(sprite, pos);
}
void Canvas::renderScore(int score) {
const int x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN);
2021-07-08 14:57:18 +00:00
const int y = (TOP_MARGIN * 2);
sf::Text text;
text.setPosition(x, y);
text.setFont(game_font);
text.setString(fmt::format("SCORE\n{}", score));
text.setCharacterSize(40);
text.setFillColor(sf::Color::White);
window.draw(text);
}
2021-06-24 08:44:13 +00:00
void Canvas::renderLives(int lives) {
2021-07-05 09:46:49 +00:00
constexpr GridPosition liveSprite = Atlas::pacman_left_narrow;
const size_t x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN);
const size_t y = TARGET_MAZE_HEIGHT;
2021-06-24 11:32:52 +00:00
Sprite pacmanSprite = getSprite(liveSprite);
for (int i = 0; i < lives - 1; i++) {
2021-08-02 13:28:07 +00:00
auto life_position = i * SPRITE_WIDTH * 1.5f;
sf::Vector2f pos{ x + life_position, y };
pacmanSprite.setPosition(pos.x, pos.y);
2021-06-24 11:32:52 +00:00
window.draw(pacmanSprite);
}
2021-06-24 08:44:13 +00:00
}
Rect Canvas::viewDimensions() {
2021-07-08 14:57:18 +00:00
const double width = (LEFT_MARGIN + TARGET_MAZE_WIDTH + SCORE_WIDTH);
const double height = (TOP_MARGIN + TARGET_MAZE_HEIGHT + BOTTOM_MARGIN);
return { 0, 0, int(width), int(height) };
}
2021-07-05 09:46:49 +00:00
Sprite Canvas::getSprite(GridPosition coordinate) const {
sf::Sprite sprite;
sprite.setTexture(sprites_texture);
sprite.setTextureRect(sf::IntRect{ int(coordinate.x * SPRITE_WIDTH),
int(coordinate.y * SPRITE_HEIGHT),
SPRITE_WIDTH,
SPRITE_HEIGHT });
return sprite;
}
2021-06-22 10:00:29 +00:00
void Canvas::renderSprite(Sprite sprite, Position pos) {
pos.x = LEFT_MARGIN + (pos.x * SPRITE_WIDTH);
2021-07-08 14:57:18 +00:00
pos.y = TOP_MARGIN + (pos.y * SPRITE_HEIGHT);
2021-08-02 13:28:07 +00:00
sprite.setPosition(float(pos.x), float(pos.y));
window.draw(sprite);
}
static void exitFailure(const std::string & message) {
fmt::print("{}\n", message);
exit(1);
}
sf::Texture Canvas::loadTexture(std::string_view path) {
sf::Texture texture;
if (!texture.loadFromFile(std::string{ path })) {
exitFailure(fmt::format("Failed to load image {}", path));
}
return texture;
}
sf::Font Canvas::loadFont(std::string_view path) {
sf::Font font;
2021-07-06 18:48:29 +00:00
if (!font.loadFromFile("retro_font.ttf")) {
exitFailure(fmt::format("Failed to load font {}", path));
}
return font;
}
2021-07-05 12:10:01 +00:00
} // namespace pacman