Canvas rewrite (#6)
* Beginning rewrite * Move all constants to canvas, wire sprite handling code * Make Sprite a struct and reformat * Fix warning Co-authored-by: Corentin Jabot <corentinjabot@gmail.com>
This commit is contained in:
parent
dad36d7362
commit
68f63f3f66
18 changed files with 333 additions and 284 deletions
|
@ -49,7 +49,7 @@ Board::Board() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Board::isWalkable(Position point, float position_delta, Direction direction) const {
|
bool Board::isWalkable(Position point, float position_delta, Direction direction) const {
|
||||||
if(point.x <= 0 || point.x >= COLUMNS-1)
|
if (point.x <= 0 || point.x >= COLUMNS - 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
|
@ -72,7 +72,7 @@ std::vector<SDL_Point> Board::initialPelletPositions() const {
|
||||||
for (uint8_t row = 0; row < ROWS; row++) {
|
for (uint8_t row = 0; row < ROWS; row++) {
|
||||||
for (uint8_t column = 0; column < COLUMNS; column++) {
|
for (uint8_t column = 0; column < COLUMNS; column++) {
|
||||||
if (board_state[row][column] == 1)
|
if (board_state[row][column] == 1)
|
||||||
positions.push_back({column, row});
|
positions.push_back({ column, row });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return positions;
|
return positions;
|
||||||
|
@ -83,7 +83,7 @@ std::vector<SDL_Point> Board::initialSuperPelletPositions() const {
|
||||||
for (uint8_t row = 0; row < ROWS; row++) {
|
for (uint8_t row = 0; row < ROWS; row++) {
|
||||||
for (uint8_t column = 0; column < COLUMNS; column++) {
|
for (uint8_t column = 0; column < COLUMNS; column++) {
|
||||||
if (board_state[row][column] == 4)
|
if (board_state[row][column] == 4)
|
||||||
positions.push_back({column, row});
|
positions.push_back({ column, row });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return positions;
|
return positions;
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] std::vector<SDL_Point> initialSuperPelletPositions() const;
|
[[nodiscard]] std::vector<SDL_Point> initialSuperPelletPositions() const;
|
||||||
|
|
||||||
static Position initialPacManPosition() { return {14, 23}; }
|
static Position initialPacManPosition() { return { 14, 23 }; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t board_state[ROWS][COLUMNS]{};
|
uint8_t board_state[ROWS][COLUMNS]{};
|
||||||
|
|
71
lib/Canvas.cpp
Normal file
71
lib/Canvas.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "Canvas.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "PacMan.hpp"
|
||||||
|
#include "Pellets.hpp"
|
||||||
|
#include "SuperPellets.hpp"
|
||||||
|
|
||||||
|
Canvas::Canvas()
|
||||||
|
: window(windowDimensions()) {}
|
||||||
|
|
||||||
|
void Canvas::update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets) {
|
||||||
|
window.clear();
|
||||||
|
|
||||||
|
renderMaze();
|
||||||
|
renderPellets(pellets);
|
||||||
|
renderSuperPellets(superPellets);
|
||||||
|
renderPacMan(pacMan);
|
||||||
|
|
||||||
|
window.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::renderMaze() const {
|
||||||
|
SDL_Rect maze_translated = { LEFT_MARGIN, TOP_MARGIN, MAZE_WIDTH, MAZE_HEIGHT };
|
||||||
|
Sprite maze = window.getBackground();
|
||||||
|
window.renderSprite(maze, maze_translated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::renderPellets(const Pellets & pellets) const {
|
||||||
|
Sprite pellet = getSprite(pellets.currentSprite());
|
||||||
|
std::vector<SDL_Point> pelletPositions = pellets.currentPositions();
|
||||||
|
for (const auto & pos : pelletPositions) {
|
||||||
|
renderSprite(pellet, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::renderSuperPellets(const SuperPellets & superPellets) const {
|
||||||
|
Sprite pellet = getSprite(superPellets.currentSprite());
|
||||||
|
std::vector<SDL_Point> superPelletPositions = superPellets.currentPositions();
|
||||||
|
for (const auto & pos : superPelletPositions) {
|
||||||
|
renderSprite(pellet, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::renderPacMan(const PacMan & pac_man) const {
|
||||||
|
Sprite pacmanSprite = getSprite(pac_man.currentSprite());
|
||||||
|
const auto & pos = pac_man.position();
|
||||||
|
renderSprite(pacmanSprite, SDL_Point{ int(pos.x), int(pos.y) });
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect Canvas::windowDimensions() const {
|
||||||
|
return { 0, 0, LEFT_MARGIN + MAZE_WIDTH + SCORE_WIDTH, TOP_MARGIN + MAZE_HEIGHT + BOTTOM_MARGIN };
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite Canvas::getSprite(SDL_Point coordinate) const {
|
||||||
|
return window.getSprite(
|
||||||
|
{ coordinate.x * DEFAULT_SPRITE_WIDTH,
|
||||||
|
coordinate.y * DEFAULT_SPRITE_HEIGHT,
|
||||||
|
DEFAULT_SPRITE_WIDTH,
|
||||||
|
DEFAULT_SPRITE_HEIGHT });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::renderSprite(Sprite sprite, SDL_Point point) const {
|
||||||
|
SDL_Rect target = {
|
||||||
|
LEFT_MARGIN + int((point.x * DEFAULT_SPRITE_WIDTH - sprite.rect.w / 2) * TEXTURE_SCALE_FACTOR),
|
||||||
|
TOP_MARGIN + int((point.y * DEFAULT_SPRITE_WIDTH - sprite.rect.h / 2) * TEXTURE_SCALE_FACTOR),
|
||||||
|
sprite.rect.w,
|
||||||
|
sprite.rect.h
|
||||||
|
};
|
||||||
|
window.renderSprite(sprite, target);
|
||||||
|
}
|
34
lib/Canvas.hpp
Normal file
34
lib/Canvas.hpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SDLWindow.hpp"
|
||||||
|
|
||||||
|
class PacMan;
|
||||||
|
class Pellets;
|
||||||
|
class SuperPellets;
|
||||||
|
|
||||||
|
class Canvas {
|
||||||
|
public:
|
||||||
|
Canvas();
|
||||||
|
void update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets);
|
||||||
|
|
||||||
|
private:
|
||||||
|
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_SPRITE_WIDTH = 32;
|
||||||
|
static constexpr int16_t DEFAULT_SPRITE_HEIGHT = 32;
|
||||||
|
static constexpr float TEXTURE_SCALE_FACTOR = 0.5;
|
||||||
|
|
||||||
|
void renderMaze() const;
|
||||||
|
void renderPacMan(const PacMan & pac_man) const;
|
||||||
|
void renderPellets(const Pellets & pellets) const;
|
||||||
|
void renderSuperPellets(const SuperPellets & superPellets) const;
|
||||||
|
void renderSprite(Sprite sprite, SDL_Point point) const;
|
||||||
|
|
||||||
|
SDL_Rect windowDimensions() const;
|
||||||
|
Sprite getSprite(SDL_Point rect) const;
|
||||||
|
SDLWindow window;
|
||||||
|
};
|
|
@ -20,7 +20,7 @@ void Game::run() {
|
||||||
auto milli_delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_delta);
|
auto milli_delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_delta);
|
||||||
pacMan.update(milli_delta, inputState, board);
|
pacMan.update(milli_delta, inputState, board);
|
||||||
current_time += time_delta;
|
current_time += time_delta;
|
||||||
window.update(pacMan, pellets, superPellets);
|
canvas.update(pacMan, pellets, superPellets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Board.hpp"
|
#include "Board.hpp"
|
||||||
#include "GameWindow.hpp"
|
#include "Canvas.hpp"
|
||||||
#include "PacMan.hpp"
|
#include "PacMan.hpp"
|
||||||
#include "Pellets.hpp"
|
#include "Pellets.hpp"
|
||||||
#include "SuperPellets.hpp"
|
#include "SuperPellets.hpp"
|
||||||
|
@ -15,7 +15,7 @@ public:
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GameWindow window;
|
Canvas canvas;
|
||||||
Board board;
|
Board board;
|
||||||
PacMan pacMan;
|
PacMan pacMan;
|
||||||
Pellets pellets;
|
Pellets pellets;
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
#include "GameWindow.hpp"
|
|
||||||
|
|
||||||
#include <SDL2/SDL_image.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "PacMan.hpp"
|
|
||||||
#include "Pellets.hpp"
|
|
||||||
#include "SuperPellets.hpp"
|
|
||||||
|
|
||||||
GameWindow::GameWindow() {
|
|
||||||
initSDL();
|
|
||||||
initSDLImage();
|
|
||||||
|
|
||||||
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);
|
|
||||||
maze_texture = loadTexture(sdl_renderer, "maze.png");
|
|
||||||
sprite_texture = loadTexture(sdl_renderer, "sprites32.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets) {
|
|
||||||
SDL_RenderClear(renderer.get());
|
|
||||||
|
|
||||||
renderMaze();
|
|
||||||
renderPellets(pellets);
|
|
||||||
renderSuperPellets(superPellets);
|
|
||||||
renderPacMan(pacMan);
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::renderMaze() const {
|
|
||||||
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 = textureGeometry(superPellets.currentSprite());
|
|
||||||
std::vector<SDL_Point> superPelletPositions = superPellets.currentPositions();
|
|
||||||
for (const auto & pos : superPelletPositions) {
|
|
||||||
renderTexture(sprite_texture.get(), sprite_rect, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::renderPellets(const Pellets & pellets) const {
|
|
||||||
SDL_Rect sprite_rect = textureGeometry(pellets.currentSprite());
|
|
||||||
std::vector<SDL_Point> pelletPositions = pellets.currentPositions();
|
|
||||||
for (const auto & pos : pelletPositions) {
|
|
||||||
renderTexture(sprite_texture.get(), sprite_rect, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::renderPacMan(const PacMan & pac_man) const {
|
|
||||||
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::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, 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::initSDL() {
|
|
||||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
|
||||||
exitFailure("Failed to initialize the SDL2 library");
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::initSDLImage() {
|
|
||||||
int img_flags = IMG_INIT_PNG;
|
|
||||||
if (IMG_Init(img_flags) != img_flags)
|
|
||||||
exitImgFailure("Failed to init SDL_Image with png");
|
|
||||||
}
|
|
||||||
|
|
||||||
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 | SDL_WINDOW_ALLOW_HIGHDPI));
|
|
||||||
|
|
||||||
if (!window)
|
|
||||||
exitFailure("Failed to create window");
|
|
||||||
|
|
||||||
return window.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Renderer * GameWindow::createRenderer(SDL_Window * sdl_window) {
|
|
||||||
renderer = std::unique_ptr<SDL_Renderer, SDL_Renderer_Deleter>(SDL_CreateRenderer(
|
|
||||||
sdl_window,
|
|
||||||
-1,
|
|
||||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
|
|
||||||
|
|
||||||
if (!renderer)
|
|
||||||
exitFailure("Failed to create renderer");
|
|
||||||
|
|
||||||
return renderer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::createWindowSurface(SDL_Window * sdl_window) {
|
|
||||||
window_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(SDL_GetWindowSurface(sdl_window));
|
|
||||||
if (!window_surface)
|
|
||||||
exitFailure("Failed to get the surface from the window");
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::setDrawColor(SDL_Renderer * sdl_renderer) {
|
|
||||||
if (SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE) < 0)
|
|
||||||
exitFailure("Failed to set renderer color");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>
|
|
||||||
GameWindow::loadTexture(SDL_Renderer * sdl_renderer, const std::string & path) {
|
|
||||||
auto surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(IMG_Load(path.c_str()));
|
|
||||||
if (!surface)
|
|
||||||
exitImgFailure("Failed to load image");
|
|
||||||
|
|
||||||
auto texture = std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>(
|
|
||||||
SDL_CreateTextureFromSurface(sdl_renderer, surface.get()));
|
|
||||||
if (!texture)
|
|
||||||
exitFailure("Failed to create texture from surface");
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::exitFailure(const std::string & message) {
|
|
||||||
std::cerr << message << "\n";
|
|
||||||
std::cerr << "SDL2 Error: " << SDL_GetError() << "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameWindow::exitImgFailure(const std::string & message) {
|
|
||||||
std::cerr << message << "\n";
|
|
||||||
std::cerr << "SDL2_Image Error: " << IMG_GetError() << "\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
struct SDL_Window_Deleter {
|
|
||||||
void operator()(SDL_Window * window) {
|
|
||||||
SDL_DestroyWindow(window);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SDL_Renderer_Deleter {
|
|
||||||
void operator()(SDL_Renderer * renderer) {
|
|
||||||
SDL_DestroyRenderer(renderer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SDL_Surface_Deleter {
|
|
||||||
void operator()(SDL_Surface * surface) {
|
|
||||||
SDL_FreeSurface(surface);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SDL_Texture_Deleter {
|
|
||||||
void operator()(SDL_Texture * texture) {
|
|
||||||
SDL_DestroyTexture(texture);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureSize {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PacMan;
|
|
||||||
class Pellets;
|
|
||||||
class SuperPellets;
|
|
||||||
|
|
||||||
class GameWindow {
|
|
||||||
public:
|
|
||||||
explicit GameWindow();
|
|
||||||
|
|
||||||
void update(const PacMan & pacMan, const Pellets & pellets, const SuperPellets & superPellets);
|
|
||||||
|
|
||||||
private:
|
|
||||||
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;
|
|
||||||
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter> maze_texture;
|
|
||||||
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter> sprite_texture;
|
|
||||||
|
|
||||||
SDL_Window * createWindow(int width, int height);
|
|
||||||
|
|
||||||
SDL_Renderer * createRenderer(SDL_Window * window);
|
|
||||||
|
|
||||||
void createWindowSurface(SDL_Window * sdl_window);
|
|
||||||
|
|
||||||
static void initSDL();
|
|
||||||
|
|
||||||
static void initSDLImage();
|
|
||||||
|
|
||||||
static void setDrawColor(SDL_Renderer * sdl_renderer);
|
|
||||||
|
|
||||||
static void exitFailure(const std::string & message);
|
|
||||||
|
|
||||||
static void exitImgFailure(const std::string & message);
|
|
||||||
|
|
||||||
static std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>
|
|
||||||
loadTexture(SDL_Renderer * sdl_renderer, const std::string & path);
|
|
||||||
|
|
||||||
void renderMaze() const;
|
|
||||||
|
|
||||||
void renderPacMan(const PacMan & pac_man) const;
|
|
||||||
|
|
||||||
void renderPellets(const Pellets & pellets) const;
|
|
||||||
|
|
||||||
void renderSuperPellets(const SuperPellets & superPellets) 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;
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "PacMan.hpp"
|
#include "PacMan.hpp"
|
||||||
|
|
||||||
PacMan::PacMan(const Board & board) :
|
PacMan::PacMan(const Board & board)
|
||||||
pos(board.initialPacManPosition()) {}
|
: pos(board.initialPacManPosition()) {}
|
||||||
|
|
||||||
SDL_Point PacMan::currentSprite() const {
|
SDL_Point PacMan::currentSprite() const {
|
||||||
return pacManAnimation.animationFrame(direction);
|
return pacManAnimation.animationFrame(direction);
|
||||||
|
@ -36,10 +36,9 @@ void PacMan::updateMazePosition(std::chrono::milliseconds time_delta, const Boar
|
||||||
float position_delta = std::min(1.0, (time_delta.count() / 128.0));
|
float position_delta = std::min(1.0, (time_delta.count() / 128.0));
|
||||||
|
|
||||||
// Handle teleport
|
// Handle teleport
|
||||||
if(pos.x >= COLUMNS-1 && direction == Direction::RIGHT) {
|
if (pos.x >= COLUMNS - 1 && direction == Direction::RIGHT) {
|
||||||
pos.x = -1;
|
pos.x = -1;
|
||||||
}
|
} else if (pos.x <= 0 && direction == Direction::LEFT) {
|
||||||
else if(pos.x <= 0 && direction == Direction::LEFT) {
|
|
||||||
pos.x = COLUMNS;
|
pos.x = COLUMNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Direction.hpp"
|
#include "Direction.hpp"
|
||||||
#include "Position.hpp"
|
|
||||||
#include "PacManAnimation.hpp"
|
#include "PacManAnimation.hpp"
|
||||||
|
#include "Position.hpp"
|
||||||
|
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -21,7 +21,6 @@ public:
|
||||||
void update(std::chrono::milliseconds time_delta, InputState state, const Board & board);
|
void update(std::chrono::milliseconds time_delta, InputState state, const Board & board);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Direction direction = Direction::NONE;
|
Direction direction = Direction::NONE;
|
||||||
Direction desired_direction = Direction::NONE;
|
Direction desired_direction = Direction::NONE;
|
||||||
Position pos;
|
Position pos;
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
SDL_Point PacManAnimation::animationFrame(Direction direction) const {
|
SDL_Point PacManAnimation::animationFrame(Direction direction) const {
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case Direction::NONE:
|
|
||||||
return closed;
|
|
||||||
case Direction::LEFT:
|
case Direction::LEFT:
|
||||||
return left_animation[animation_position];
|
return left_animation[animation_position];
|
||||||
case Direction::RIGHT:
|
case Direction::RIGHT:
|
||||||
|
@ -12,6 +10,9 @@ SDL_Point PacManAnimation::animationFrame(Direction direction) const {
|
||||||
return up_animation[animation_position];
|
return up_animation[animation_position];
|
||||||
case Direction::DOWN:
|
case Direction::DOWN:
|
||||||
return down_animation[animation_position];
|
return down_animation[animation_position];
|
||||||
|
case Direction::NONE:
|
||||||
|
default:
|
||||||
|
return closed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Position.hpp"
|
|
||||||
#include "Board.hpp"
|
#include "Board.hpp"
|
||||||
|
#include "Position.hpp"
|
||||||
|
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
|
|
||||||
|
|
113
lib/SDLWindow.cpp
Normal file
113
lib/SDLWindow.cpp
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#include "SDLWindow.hpp"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_image.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
SDLWindow::SDLWindow(SDL_Rect windowGeometry) {
|
||||||
|
initSDL();
|
||||||
|
initSDLImage();
|
||||||
|
|
||||||
|
createWindow(windowGeometry.w, windowGeometry.h);
|
||||||
|
createRenderer();
|
||||||
|
createWindowSurface();
|
||||||
|
setDrawColor();
|
||||||
|
maze_texture = loadTexture("maze.png");
|
||||||
|
sprite_texture = loadTexture("sprites32.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::clear() {
|
||||||
|
SDL_RenderClear(renderer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::render() {
|
||||||
|
SDL_RenderPresent(renderer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite SDLWindow::getBackground() const {
|
||||||
|
int w, h;
|
||||||
|
if (SDL_QueryTexture(maze_texture.get(), nullptr, nullptr, &w, &h) != 0) {
|
||||||
|
exitFailure("Failed to get texture geometry");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect maze_rect = { 0, 0, w, h };
|
||||||
|
return { maze_texture.get(), maze_rect };
|
||||||
|
}
|
||||||
|
|
||||||
|
Sprite SDLWindow::getSprite(SDL_Rect rect) const {
|
||||||
|
return { sprite_texture.get(), rect };
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::renderSprite(Sprite sprite, SDL_Rect target) const {
|
||||||
|
if (SDL_RenderCopy(renderer.get(), sprite.texture, &sprite.rect, &target) < 0)
|
||||||
|
exitFailure("Failed to copy texture to renderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::initSDL() {
|
||||||
|
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
||||||
|
exitFailure("Failed to initialize the SDL2 library");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::initSDLImage() {
|
||||||
|
int img_flags = IMG_INIT_PNG;
|
||||||
|
if (IMG_Init(img_flags) != img_flags)
|
||||||
|
exitImgFailure("Failed to init SDL_Image with png");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::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 | SDL_WINDOW_ALLOW_HIGHDPI));
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
exitFailure("Failed to create window");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::createRenderer() {
|
||||||
|
renderer = std::unique_ptr<SDL_Renderer, SDL_Renderer_Deleter>(SDL_CreateRenderer(
|
||||||
|
window.get(),
|
||||||
|
-1,
|
||||||
|
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
|
||||||
|
|
||||||
|
if (!renderer)
|
||||||
|
exitFailure("Failed to create renderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::createWindowSurface() {
|
||||||
|
window_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(SDL_GetWindowSurface(window.get()));
|
||||||
|
if (!window_surface)
|
||||||
|
exitFailure("Failed to get the surface from the window");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::setDrawColor() {
|
||||||
|
if (SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, SDL_ALPHA_OPAQUE) < 0)
|
||||||
|
exitFailure("Failed to set renderer color");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>
|
||||||
|
SDLWindow::loadTexture(const std::string & path) {
|
||||||
|
auto surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>(IMG_Load(path.c_str()));
|
||||||
|
if (!surface)
|
||||||
|
exitImgFailure("Failed to load image");
|
||||||
|
|
||||||
|
auto texture = std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>(
|
||||||
|
SDL_CreateTextureFromSurface(renderer.get(), surface.get()));
|
||||||
|
if (!texture)
|
||||||
|
exitFailure("Failed to create texture from surface");
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::exitFailure(const std::string & message) {
|
||||||
|
std::cerr << message << "\n";
|
||||||
|
std::cerr << "SDL2 Error: " << SDL_GetError() << "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::exitImgFailure(const std::string & message) {
|
||||||
|
std::cerr << message << "\n";
|
||||||
|
std::cerr << "SDL2_Image Error: " << IMG_GetError() << "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
82
lib/SDLWindow.hpp
Normal file
82
lib/SDLWindow.hpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Sprite.hpp"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct SDL_Window_Deleter {
|
||||||
|
void operator()(SDL_Window * window) {
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SDL_Renderer_Deleter {
|
||||||
|
void operator()(SDL_Renderer * renderer) {
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SDL_Surface_Deleter {
|
||||||
|
void operator()(SDL_Surface * surface) {
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SDL_Texture_Deleter {
|
||||||
|
void operator()(SDL_Texture * texture) {
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureSize {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PacMan;
|
||||||
|
class Pellets;
|
||||||
|
class SuperPellets;
|
||||||
|
|
||||||
|
class SDLWindow {
|
||||||
|
public:
|
||||||
|
explicit SDLWindow(SDL_Rect windowGeometry);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
Sprite getBackground() const;
|
||||||
|
Sprite getSprite(SDL_Rect rect) const;
|
||||||
|
void renderSprite(Sprite sprite, SDL_Rect target) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr int16_t SCALE_FACTOR = 1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter> maze_texture;
|
||||||
|
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter> sprite_texture;
|
||||||
|
|
||||||
|
void createWindow(int width, int height);
|
||||||
|
|
||||||
|
void createRenderer();
|
||||||
|
|
||||||
|
void createWindowSurface();
|
||||||
|
|
||||||
|
static void initSDL();
|
||||||
|
|
||||||
|
static void initSDLImage();
|
||||||
|
|
||||||
|
void setDrawColor();
|
||||||
|
|
||||||
|
static void exitFailure(const std::string & message);
|
||||||
|
|
||||||
|
static void exitImgFailure(const std::string & message);
|
||||||
|
|
||||||
|
std::unique_ptr<SDL_Texture, SDL_Texture_Deleter>
|
||||||
|
loadTexture(const std::string & path);
|
||||||
|
|
||||||
|
SDL_Rect windowDimensions() const;
|
||||||
|
};
|
1
lib/Sprite.cpp
Normal file
1
lib/Sprite.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "Sprite.hpp"
|
9
lib/Sprite.hpp
Normal file
9
lib/Sprite.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Sprite {
|
||||||
|
SDL_Texture * texture;
|
||||||
|
SDL_Rect rect;
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
#include "SuperPellets.hpp"
|
#include "SuperPellets.hpp"
|
||||||
|
|
||||||
SuperPellets::SuperPellets(const Board & board) :
|
SuperPellets::SuperPellets(const Board & board)
|
||||||
positions(board.initialSuperPelletPositions()) {}
|
: positions(board.initialSuperPelletPositions()) {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Position.hpp"
|
|
||||||
#include "Board.hpp"
|
#include "Board.hpp"
|
||||||
|
#include "Position.hpp"
|
||||||
|
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue