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>
Game::Game() :
window(448, 496),
board(),
pacMan(board),
Game::Game()
: pacMan(board),
pellets(board),
superPellets(board) {}

View file

@ -8,10 +8,13 @@
#include "Pellets.hpp"
#include "SuperPellets.hpp"
GameWindow::GameWindow(int width, int height) {
GameWindow::GameWindow() {
initSDL();
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);
createWindowSurface(sdl_window);
setDrawColor(sdl_renderer);
@ -31,47 +34,54 @@ void GameWindow::update(const PacMan & pacMan, const Pellets & pellets, const Su
}
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 {
SDL_Rect sprite_rect = superPellets.currentSprite();
SDL_Rect sprite_rect = textureGeometry(superPellets.currentSprite());
std::vector<SDL_Point> superPelletPositions = superPellets.currentPositions();
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, &maze_rect);
renderTexture(sprite_texture.get(), sprite_rect, pos);
}
}
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();
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, &maze_rect);
renderTexture(sprite_texture.get(), sprite_rect, pos);
}
}
void GameWindow::renderPacMan(const PacMan & pac_man) const {
Position maze_position = pac_man.position();
SDL_Rect maze_rect = targetRect(maze_position, 8 * SCALE_FACTOR);
SDL_Rect sprite_rect = pac_man.currentSprite();
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
SDL_Rect sprite_rect = textureGeometry(pac_man.currentSprite());
Position pacman_pos = pac_man.position();
renderTexture(sprite_texture.get(), sprite_rect, SDL_Point{ int(pacman_pos.x), int(pacman_pos.y) });
}
SDL_Rect GameWindow::targetRect(const Position & position, int pixel_increase) {
int pixels = 16 * SCALE_FACTOR;
int displacement = pixel_increase / 2;
return {
int(pixels * position.x) - displacement,
int(pixels * position.y) - displacement,
(pixels + pixel_increase),
(pixels + pixel_increase)
SDL_Rect GameWindow::textureGeometry(SDL_Point p) const {
return { p.x * 32, p.y * 32, 32, 32 };
}
SDL_Rect GameWindow::windowDimensions() const {
return { 0, 0, LEFT_MARGIN + MAZE_WIDTH + SCORE_WIDTH, TOP_MARGIN + MAZE_HEIGHT + BOTTOM_MARGIN };
}
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 {
if (SDL_RenderCopy(renderer.get(), texture, texture_rect, target_rect) < 0)
void GameWindow::renderTexture(SDL_Texture * texture, const SDL_Rect & src, const SDL_Rect & target) const {
if (SDL_RenderCopy(renderer.get(), texture, &src, &target) < 0)
exitFailure("Failed to copy texture to renderer");
}
@ -88,12 +98,12 @@ void GameWindow::initSDLImage() {
SDL_Window * GameWindow::createWindow(int width, int height) {
window = std::unique_ptr<SDL_Window, SDL_Window_Deleter>(SDL_CreateWindow(
"Pacman",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
width,
height,
SDL_WINDOW_OPENGL));
"Pacman",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
width,
height,
SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI));
if (!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 Pellets;
class Position;
//class Position;
class SuperPellets;
class GameWindow {
public:
explicit GameWindow(int width, int height);
explicit GameWindow();
void update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets);
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_Renderer, SDL_Renderer_Deleter> renderer;
std::unique_ptr<SDL_Surface, SDL_Surface_Deleter> window_surface;
@ -74,7 +89,15 @@ private:
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) :
pos(board.initialPacManPosition()) {}
SDL_Rect PacMan::currentSprite() const {
SDL_Point PacMan::currentSprite() const {
return pacManAnimation.animationFrame(direction);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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