Change window geometry for scoring.

* Add margins all around the board for better aestetics.
* Add room for scoring
* Because the texture atlas is a 32x32 grid, we can manipulate
textures as positions on that grid and only create a rectangle
for that texture in the rendering code.
* Avoid hardcoded values in the rendering code.
This commit is contained in:
Corentin Jabot 2021-06-15 23:54:35 +02:00
parent 27b8d47dec
commit bbf3731cf4
10 changed files with 92 additions and 62 deletions

View file

@ -2,10 +2,8 @@
#include <chrono> #include <chrono>
Game::Game() : Game::Game()
window(448, 496), : pacMan(board),
board(),
pacMan(board),
pellets(board), pellets(board),
superPellets(board) {} superPellets(board) {}

View file

@ -8,10 +8,13 @@
#include "Pellets.hpp" #include "Pellets.hpp"
#include "SuperPellets.hpp" #include "SuperPellets.hpp"
GameWindow::GameWindow(int width, int height) { GameWindow::GameWindow() {
initSDL(); initSDL();
initSDLImage(); initSDLImage();
auto sdl_window = createWindow(width * SCALE_FACTOR, height * SCALE_FACTOR);
const auto window_dimension = windowDimensions();
auto sdl_window = createWindow(window_dimension.w, window_dimension.h);
auto sdl_renderer = createRenderer(sdl_window); auto sdl_renderer = createRenderer(sdl_window);
createWindowSurface(sdl_window); createWindowSurface(sdl_window);
setDrawColor(sdl_renderer); setDrawColor(sdl_renderer);
@ -31,47 +34,54 @@ void GameWindow::update(const PacMan & pacMan, const Pellets & pellets, const Su
} }
void GameWindow::renderMaze() const { void GameWindow::renderMaze() const {
renderTexture(maze_texture.get(), nullptr, nullptr); SDL_Rect maze_rect = { 0, 0, MAZE_WIDTH, MAZE_HEIGHT };
SDL_Rect maze_translated = { LEFT_MARGIN, TOP_MARGIN, MAZE_WIDTH, MAZE_HEIGHT };
renderTexture(maze_texture.get(), maze_rect, maze_translated);
} }
void GameWindow::renderSuperPellets(const SuperPellets & superPellets) const { void GameWindow::renderSuperPellets(const SuperPellets & superPellets) const {
SDL_Rect sprite_rect = superPellets.currentSprite(); SDL_Rect sprite_rect = textureGeometry(superPellets.currentSprite());
std::vector<SDL_Point> superPelletPositions = superPellets.currentPositions(); std::vector<SDL_Point> superPelletPositions = superPellets.currentPositions();
for (const auto & pos : superPelletPositions) { for (const auto & pos : superPelletPositions) {
SDL_Rect maze_rect = targetRect({float(pos.x), float(pos.y)}, 8 * SCALE_FACTOR); renderTexture(sprite_texture.get(), sprite_rect, pos);
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
} }
} }
void GameWindow::renderPellets(const Pellets & pellets) const { void GameWindow::renderPellets(const Pellets & pellets) const {
SDL_Rect sprite_rect = pellets.currentSprite(); SDL_Rect sprite_rect = textureGeometry(pellets.currentSprite());
std::vector<SDL_Point> pelletPositions = pellets.currentPositions(); std::vector<SDL_Point> pelletPositions = pellets.currentPositions();
for (const auto & pos : pelletPositions) { for (const auto & pos : pelletPositions) {
SDL_Rect maze_rect = targetRect({float(pos.x), float(pos.y)}, 8 * SCALE_FACTOR); renderTexture(sprite_texture.get(), sprite_rect, pos);
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
} }
} }
void GameWindow::renderPacMan(const PacMan & pac_man) const { void GameWindow::renderPacMan(const PacMan & pac_man) const {
Position maze_position = pac_man.position(); SDL_Rect sprite_rect = textureGeometry(pac_man.currentSprite());
SDL_Rect maze_rect = targetRect(maze_position, 8 * SCALE_FACTOR); Position pacman_pos = pac_man.position();
SDL_Rect sprite_rect = pac_man.currentSprite(); renderTexture(sprite_texture.get(), sprite_rect, SDL_Point{ int(pacman_pos.x), int(pacman_pos.y) });
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
} }
SDL_Rect GameWindow::targetRect(const Position & position, int pixel_increase) { SDL_Rect GameWindow::textureGeometry(SDL_Point p) const {
int pixels = 16 * SCALE_FACTOR; return { p.x * 32, p.y * 32, 32, 32 };
int displacement = pixel_increase / 2; }
return {
int(pixels * position.x) - displacement, SDL_Rect GameWindow::windowDimensions() const {
int(pixels * position.y) - displacement, return { 0, 0, LEFT_MARGIN + MAZE_WIDTH + SCORE_WIDTH, TOP_MARGIN + MAZE_HEIGHT + BOTTOM_MARGIN };
(pixels + pixel_increase), }
(pixels + pixel_increase)
void GameWindow::renderTexture(SDL_Texture * texture, const SDL_Rect & src, SDL_Point p) const {
SDL_Rect target = {
LEFT_MARGIN + int((p.x * DEFAULT_TEXTURE_WIDTH - src.w / 2) * TEXTURE_SCALE_FACTOR),
TOP_MARGIN + int((p.y * DEFAULT_TEXTURE_WIDTH - src.h / 2) * TEXTURE_SCALE_FACTOR),
src.w,
src.h
}; };
renderTexture(texture, src, target);
} }
void GameWindow::renderTexture(SDL_Texture * texture, SDL_Rect * texture_rect, SDL_Rect * target_rect) const { void GameWindow::renderTexture(SDL_Texture * texture, const SDL_Rect & src, const SDL_Rect & target) const {
if (SDL_RenderCopy(renderer.get(), texture, texture_rect, target_rect) < 0)
if (SDL_RenderCopy(renderer.get(), texture, &src, &target) < 0)
exitFailure("Failed to copy texture to renderer"); exitFailure("Failed to copy texture to renderer");
} }
@ -88,12 +98,12 @@ void GameWindow::initSDLImage() {
SDL_Window * GameWindow::createWindow(int width, int height) { SDL_Window * GameWindow::createWindow(int width, int height) {
window = std::unique_ptr<SDL_Window, SDL_Window_Deleter>(SDL_CreateWindow( window = std::unique_ptr<SDL_Window, SDL_Window_Deleter>(SDL_CreateWindow(
"Pacman", "Pacman",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, width,
height, height,
SDL_WINDOW_OPENGL)); SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI));
if (!window) if (!window)
exitFailure("Failed to create window"); exitFailure("Failed to create window");

View file

@ -28,19 +28,34 @@ struct SDL_Texture_Deleter {
} }
}; };
struct TextureSize {
int width;
int height;
};
class PacMan; class PacMan;
class Pellets; class Pellets;
class Position; //class Position;
class SuperPellets; class SuperPellets;
class GameWindow { class GameWindow {
public: public:
explicit GameWindow(int width, int height); explicit GameWindow();
void update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets); void update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets);
private: private:
static const int16_t SCALE_FACTOR = 1; static constexpr int16_t SCALE_FACTOR = 1;
static constexpr int16_t LEFT_MARGIN = 40;
static constexpr int16_t TOP_MARGIN = 40;
static constexpr int16_t BOTTOM_MARGIN = 40;
static constexpr int16_t MAZE_WIDTH = 448;
static constexpr int16_t MAZE_HEIGHT = 496;
static constexpr int16_t SCORE_WIDTH = 200;
static constexpr int16_t DEFAULT_TEXTURE_WIDTH = 32;
static constexpr int16_t DEFAULT_TEXTURE_HEIGHT = 32;
static constexpr float TEXTURE_SCALE_FACTOR = 0.5;
std::unique_ptr<SDL_Window, SDL_Window_Deleter> window; std::unique_ptr<SDL_Window, SDL_Window_Deleter> window;
std::unique_ptr<SDL_Renderer, SDL_Renderer_Deleter> renderer; std::unique_ptr<SDL_Renderer, SDL_Renderer_Deleter> renderer;
std::unique_ptr<SDL_Surface, SDL_Surface_Deleter> window_surface; std::unique_ptr<SDL_Surface, SDL_Surface_Deleter> window_surface;
@ -74,7 +89,15 @@ private:
void renderSuperPellets(const SuperPellets & superPellets) const; void renderSuperPellets(const SuperPellets & superPellets) const;
static SDL_Rect targetRect(const Position & position, int pixel_increase); //static SDL_Rect targetRect(const Position & position, int pixel_increase);
void renderTexture(SDL_Texture * texture, SDL_Rect * texture_rect, SDL_Rect * target_rect) const; SDL_Rect windowDimensions() const;
// Given an x - y coordinate of a texture in the assets file,
// returns a rectangle for the whole texture.
// Assumes texture are laid out in a 32x32 grid
SDL_Rect textureGeometry(SDL_Point) const;
void renderTexture(SDL_Texture * texture, const SDL_Rect & src, SDL_Point) const;
void renderTexture(SDL_Texture * texture, const SDL_Rect & src, const SDL_Rect & target) const;
}; };

View file

@ -3,7 +3,7 @@
PacMan::PacMan(const Board & board) : PacMan::PacMan(const Board & board) :
pos(board.initialPacManPosition()) {} pos(board.initialPacManPosition()) {}
SDL_Rect PacMan::currentSprite() const { SDL_Point PacMan::currentSprite() const {
return pacManAnimation.animationFrame(direction); return pacManAnimation.animationFrame(direction);
} }

View file

@ -14,7 +14,7 @@ class PacMan {
public: public:
explicit PacMan(const Board & board); explicit PacMan(const Board & board);
[[nodiscard]] SDL_Rect currentSprite() const; [[nodiscard]] SDL_Point currentSprite() const;
[[nodiscard]] Position position() const; [[nodiscard]] Position position() const;

View file

@ -1,6 +1,6 @@
#include "PacManAnimation.hpp" #include "PacManAnimation.hpp"
SDL_Rect PacManAnimation::animationFrame(Direction direction) const { SDL_Point PacManAnimation::animationFrame(Direction direction) const {
switch (direction) { switch (direction) {
case Direction::NONE: case Direction::NONE:
return closed; return closed;

View file

@ -10,25 +10,24 @@
class PacManAnimation { class PacManAnimation {
public: public:
[[nodiscard]] SDL_Point animationFrame(Direction direction) const;
[[nodiscard]] SDL_Rect animationFrame(Direction direction) const;
void updateAnimationPosition(std::chrono::milliseconds time_delta); void updateAnimationPosition(std::chrono::milliseconds time_delta);
private: private:
uint8_t animation_position = 0; uint8_t animation_position = 0;
float animation_position_delta = 0.0; float animation_position_delta = 0.0;
const SDL_Rect right_wide = {0 * 32, 0 * 32, 32, 32}; const SDL_Point right_wide = { 0, 0 };
const SDL_Rect right_narrow = {1 * 32, 0 * 32, 32, 32}; const SDL_Point right_narrow = { 1, 0 };
const SDL_Rect closed = {2 * 32, 0 * 32, 32, 32}; const SDL_Point closed = { 2, 0 };
const SDL_Rect left_narrow = {3 * 32, 0 * 32, 32, 32}; const SDL_Point left_narrow = { 3, 0 };
const SDL_Rect left_wide = {4 * 32, 0 * 32, 32, 32}; const SDL_Point left_wide = { 4, 0 };
const SDL_Rect up_wide = {5 * 32, 0 * 32, 32, 32}; const SDL_Point up_wide = { 5, 0 };
const SDL_Rect up_narrow = {6 * 32, 0 * 32, 32, 32}; const SDL_Point up_narrow = { 6, 0 };
const SDL_Rect down_wide = {7 * 32, 0 * 32, 32, 32}; const SDL_Point down_wide = { 7, 0 };
const SDL_Rect down_narrow = {8 * 32, 0 * 32, 32, 32}; const SDL_Point down_narrow = { 8, 0 };
const SDL_Rect down_animation[4]{down_wide, down_narrow, closed, down_narrow}; const SDL_Point down_animation[4]{ down_wide, down_narrow, closed, down_narrow };
const SDL_Rect left_animation[4]{left_wide, left_narrow, closed, left_narrow}; const SDL_Point left_animation[4]{ left_wide, left_narrow, closed, left_narrow };
const SDL_Rect right_animation[4]{right_wide, right_narrow, closed, right_narrow}; const SDL_Point right_animation[4]{ right_wide, right_narrow, closed, right_narrow };
const SDL_Rect up_animation[4]{up_wide, up_narrow, closed, up_narrow}; const SDL_Point up_animation[4]{ up_wide, up_narrow, closed, up_narrow };
}; };

View file

@ -1,4 +1,4 @@
#include "Pellets.hpp" #include "Pellets.hpp"
Pellets::Pellets(const Board & board) : Pellets::Pellets(const Board & board)
positions(board.initialPelletPositions()) {} : positions(board.initialPelletPositions()) {}

View file

@ -9,7 +9,7 @@ class Pellets {
public: public:
explicit Pellets(const Board & board); explicit Pellets(const Board & board);
[[nodiscard]] SDL_Rect currentSprite() const { [[nodiscard]] SDL_Point currentSprite() const {
return sprite; return sprite;
}; };
@ -18,6 +18,6 @@ public:
} }
private: private:
const SDL_Rect sprite = {1 * 32, 9 * 32, 32, 32}; const SDL_Point sprite = { 1, 9 };
std::vector<SDL_Point> positions; std::vector<SDL_Point> positions;
}; };

View file

@ -9,7 +9,7 @@ class SuperPellets {
public: public:
explicit SuperPellets(const Board & board); explicit SuperPellets(const Board & board);
[[nodiscard]] SDL_Rect currentSprite() const { [[nodiscard]] SDL_Point currentSprite() const {
return sprite; return sprite;
} }
@ -18,6 +18,6 @@ public:
} }
private: private:
const SDL_Rect sprite = {0 * 32, 9 * 32, 32, 32}; const SDL_Point sprite = { 0, 9 };
std::vector<SDL_Point> positions; std::vector<SDL_Point> positions;
}; };