Copy over pacman game

This commit is contained in:
Patricia Aas 2020-11-27 14:10:09 +01:00
parent 8062861808
commit ef20432d9d
25 changed files with 682 additions and 29 deletions

View file

@ -1 +0,0 @@
add_executable(01_main main.cpp)

View file

@ -1,4 +0,0 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

View file

@ -1 +0,0 @@
add_executable(02_main main.cpp)

View file

@ -1,4 +0,0 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

View file

@ -1 +0,0 @@
add_executable(11_main main.cpp)

View file

@ -1,4 +0,0 @@
#include <iostream>
int main() {
std::cout << "Hello World\n";
}

View file

@ -1,16 +1,14 @@
if (NOT APPLE AND NOT WIN32)
set(CMAKE_TOOLCHAIN_FILE toolchains/linux_clang_11.cmake)
endif ()
cmake_minimum_required(VERSION 3.10)
project(modern_cpp C CXX)
cmake_minimum_required(VERSION 3.17)
project(pacman)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS NO)
include_directories(include)
# Download automatically, you can also just copy the conan.cmake file
if (NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.15/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake")
endif ()
add_subdirectory(01_foundation)
add_subdirectory(02_foundation)
add_subdirectory(11_intermediate)
set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}/src)
add_subdirectory(src)

View file

@ -1,2 +1,43 @@
# modern_cpp_exercises
Exercises for the TurtleSec training "Mod(C++)" - Foundation and Intermediate
# Mod(C++) - Pac-Man Exercise
## Ghosts
This will probably become relevant https://en.wikipedia.org/wiki/Ghosts_(Pac-Man)
This as well https://youtu.be/ataGotQ7ir8
https://gameinternals.com/understanding-pac-man-ghost-behavior
https://www.gamasutra.com/view/feature/3938/the_pacman_dossier.php?print=1
## Windows Toolchain
Visual Studio Community 2019 - latest (MSVC 19.28.29334.0)
## Get Clion
https://www.jetbrains.com/clion/download/download-thanks.html
## Get Python 3
https://docs.python.org/3/using/windows.html#the-full-installer
## Get Conan
pip3 install conan --upgrade
## Conan on Linux
Set this environment variable and Conan will tell you which packages you need to
intall on Linux.
CONAN_SYSREQUIRES_MODE=verify
In case of link errors around sndio, try to uninstall this package and rebuild the conan cache:
~~~
sudo apt remove libsndio-dev*
~~~
https://bugzilla.libsdl.org/show_bug.cgi?id=5105
## Currently does not work on windows - Get Clang
Clang 10 works seamlessly with Conan (version 1.31.4) - with 11 you have to update your
<userhome>/.conan/settings.yml file, add "11" to the list at "clang: version:"
https://releases.llvm.org/download.html
https://www.jetbrains.com/help/clion/quick-tutorial-on-configuring-clion-on-windows.html#clang-cl

BIN
assets/maze.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 KiB

BIN
assets/sprites32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

19
conanfile.py Normal file
View file

@ -0,0 +1,19 @@
from conans import ConanFile, CMake
class ConanDependencies(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package"
default_options = {
"sdl2_image:jpg": "libjpeg"
}
def requirements(self):
self.requires("sdl2/2.0.9@bincrafters/stable")
self.requires("sdl2_image/2.0.4@bincrafters/stable")
def imports(self):
self.copy("*.dll", dst="bin", src="bin")
self.copy("*.dylib*", dst="bin", src="lib")
self.copy('*.so*', dst='lib', src='lib')
self.copy("license*", dst="licenses", folder=True, ignore_case=True)

103
src/Board.cpp Normal file
View file

@ -0,0 +1,103 @@
#include "Board.h"
// Legend
// 0 - wall
// 1 - pellet
// 2 - nothing
// 3 - door
// 4 - superpower
// 16 pixels per square
// Maze in pixels - width: 448 - height - 496
static const uint8_t board[ROWS][COLUMNS] = {
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // 0
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0}, // 1
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0}, // 2
{0,4,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,4,0}, // 3
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0}, // 4
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0}, // 5
{0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0}, // 6
{0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0}, // 7
{0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0}, // 8
{0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0}, // 9
{0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0}, // 10
{0,0,0,0,0,0,1,0,0,2,2,2,2,2,2,2,2,2,2,0,0,1,0,0,0,0,0,0}, // 11
{0,0,0,0,0,0,1,0,0,2,0,0,0,3,3,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 12
{0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 13
{3,2,2,2,2,2,1,2,2,2,0,0,0,0,0,0,0,0,2,2,2,1,2,2,2,2,2,3}, // 14
{0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 15
{0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 16
{0,0,0,0,0,0,1,0,0,2,2,2,2,2,2,2,2,2,2,0,0,1,0,0,0,0,0,0}, // 17
{0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 18
{0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0}, // 19
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0}, // 20
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0}, // 21
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0}, // 22
{0,4,1,1,0,0,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,0,0,1,1,4,0}, // 23
{0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0}, // 24
{0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0}, // 25
{0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0}, // 26
{0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0}, // 27
{0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0}, // 28
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0}, // 29
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // 30
};
Board::Board() {
resetBoardState();
}
void Board::resetBoardState() {
for (uint8_t row = 0; row < ROWS; row++)
for (uint8_t column = 0; column < COLUMNS; column++)
board_state[row][column] = board[row][column];
}
bool Board::isWalkable(Position point, float_t position_delta, Direction direction) const {
switch (direction) {
case Direction::LEFT:
return board_state[int(point.y)][int(point.x - position_delta)] != 0;
case Direction::RIGHT:
return board_state[int(point.y)][int(point.x) + 1] != 0;
case Direction::UP:
return board_state[int(point.y - position_delta)][int(point.x)] != 0;
case Direction::DOWN:
return board_state[int(point.y) + 1][int(point.x)] != 0;
case Direction::NONE:
default: return true;
}
}
SDL_Rect Board::pelletSprite() {
return pellet;
}
SDL_Rect Board::superPelletSprite() {
return super_pellet;
}
std::vector<SDL_Point> Board::pelletPositions() {
std::vector<SDL_Point> positions;
for (uint8_t row = 0; row < ROWS; row++) {
for (uint8_t column = 0; column < COLUMNS; column++) {
if (board_state[row][column] == 1)
positions.push_back({column, row});
}
}
return positions;
}
std::vector<SDL_Point> Board::superPelletPositions() {
// Hard coded is probably better than this
std::vector<SDL_Point> positions;
for (uint8_t row = 0; row < ROWS; row++) {
for (uint8_t column = 0; column < COLUMNS; column++) {
if (board_state[row][column] == 4)
positions.push_back({column, row});
}
}
return positions;
}

35
src/Board.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef PACMAN_BOARD_H
#define PACMAN_BOARD_H
#include "Direction.h"
#include "Position.h"
#include <SDL2/SDL_rect.h>
#include <cstdint>
#include <vector>
const uint8_t ROWS = 31;
const uint8_t COLUMNS = 28;
class Board {
public:
Board();
[[nodiscard]] bool isWalkable(Position point, float_t d, Direction direction) const;
SDL_Rect pelletSprite();
SDL_Rect superPelletSprite();
std::vector<SDL_Point> pelletPositions();
std::vector<SDL_Point> superPelletPositions();
private:
uint8_t board_state[ROWS][COLUMNS];
const SDL_Rect super_pellet = {0*32, 9*32, 32, 32};
const SDL_Rect pellet = {1*32, 9*32, 32, 32};
void resetBoardState();
};
#endif //PACMAN_BOARD_H

12
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,12 @@
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_add_remote(NAME bincrafters INDEX 1 URL https://api.bintray.com/conan/bincrafters/public-conan)
conan_cmake_run(CONANFILE ../conanfile.py BASIC_SETUP CMAKE_TARGETS BUILD missing)
find_package(sdl2 REQUIRED)
find_package(sdl2_image REQUIRED)
include_directories(${sdl2_INCLUDE_DIRS} ${sdl2_image_INCLUDE_DIRS})
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.cpp")
add_executable(${PROJECT_NAME} ${sources})
target_link_libraries(${PROJECT_NAME} sdl2::sdl2 sdl2_image::sdl2_image)

12
src/Direction.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PACMAN_DIRECTION_H
#define PACMAN_DIRECTION_H
enum class Direction {
NONE,
LEFT,
RIGHT,
UP,
DOWN
};
#endif //PACMAN_DIRECTION_H

60
src/Game.cpp Normal file
View file

@ -0,0 +1,60 @@
#include "Game.h"
#include <SDL2/SDL.h>
#include <chrono>
Game::Game()
: window(448*2, 496*2) {
}
auto Game::now() {
return std::chrono::system_clock::now();
}
void Game::run() {
InputState inputState;
auto current_time = now();
while (!inputState.close) {
processEvents(inputState);
auto time_delta = now() - current_time;
auto milli_delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_delta);
pacMan.update(milli_delta, inputState, board);
current_time += time_delta;
window.update(pacMan, board);
}
}
void Game::processEvents(InputState & inputState) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
inputState.close = true;
break;
case SDL_KEYDOWN:
keyToggle(event, inputState, true);
break;
case SDL_KEYUP:
keyToggle(event, inputState, false);
break;
}
}
}
void Game::keyToggle(const SDL_Event & event, InputState & inputState, bool on) {
switch (event.key.keysym.sym) {
case SDLK_UP:
inputState.up = on;
break;
case SDLK_DOWN:
inputState.down = on;
break;
case SDLK_LEFT:
inputState.left = on;
break;
case SDLK_RIGHT:
inputState.right = on;
break;
}
}

24
src/Game.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef PACMAN_GAME_H
#define PACMAN_GAME_H
#include "Board.h"
#include "GameWindow.h"
#include "InputState.h"
#include "PacMan.h"
class Game {
public:
Game();
void run();
private:
GameWindow window;
PacMan pacMan;
Board board;
static void processEvents(InputState & inputState) ;
static void keyToggle(const SDL_Event & event, InputState & inputState, bool on);
[[nodiscard]] static auto now() ;
};
#endif //PACMAN_GAME_H

149
src/GameWindow.cpp Normal file
View file

@ -0,0 +1,149 @@
#include "GameWindow.h"
#include "PacMan.h"
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
GameWindow::GameWindow(int width, int height) {
initSDL();
initSDLImage();
auto sdl_window = createWindow(width, height);
auto sdl_renderer = createRenderer(sdl_window);
createWindowSurface(sdl_window);
setDrawColor(sdl_renderer);
maze_texture = loadTexture(sdl_renderer, "../../../assets/maze.png");
sprite_texture = loadTexture(sdl_renderer, "../../../assets/sprites32.png");
}
void GameWindow::update(const PacMan & pacMan, Board board) {
SDL_RenderClear(renderer.get());
renderMaze();
renderBoard(board);
renderPacMan(pacMan);
SDL_RenderPresent(renderer.get());
}
void GameWindow::renderMaze() const {
renderTexture(maze_texture.get(), nullptr, nullptr);
}
void GameWindow::renderBoard(Board board) {
renderPellets(board);
renderSuperPellets(board);
}
void GameWindow::renderSuperPellets(Board & board) const {
SDL_Rect sprite_rect = board.superPelletSprite();
std::vector<SDL_Point> superPelletPositions = board.superPelletPositions();
for (const auto & pos : superPelletPositions) {
SDL_Rect maze_rect = targetRect({ float_t(pos.x), float_t(pos.y) }, 16);
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
}
}
void GameWindow::renderPellets(Board & board) const {
SDL_Rect sprite_rect = board.pelletSprite();
std::vector<SDL_Point> pelletPositions = board.pelletPositions();
for (const auto & pos : pelletPositions) {
SDL_Rect maze_rect = targetRect({ float_t(pos.x), float_t(pos.y) }, 16);
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
}
}
void GameWindow::renderPacMan(const PacMan & pac_man) const {
Position maze_position = pac_man.currentPosition();
SDL_Rect maze_rect = targetRect(maze_position, 16);
SDL_Rect sprite_rect = pac_man.currentSprite();
renderTexture(sprite_texture.get(), &sprite_rect, &maze_rect);
}
SDL_Rect GameWindow::targetRect(const Position & position, int pixel_increase) {
int pixels = 32;
int displacement = pixel_increase / 2;
return {
int(pixels * position.x) - displacement,
int(pixels * position.y) - displacement,
(pixels + pixel_increase),
(pixels + pixel_increase)
};
}
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)
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));
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);
}

65
src/GameWindow.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef PACMAN_GAMEWINDOW_H
#define PACMAN_GAMEWINDOW_H
#include <memory>
#include <string>
#include "PacMan.h"
#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);
}
};
class PacMan;
class GameWindow {
public:
explicit GameWindow(int width, int height);
void update(const PacMan & pacMan, Board board);
private:
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 renderBoard(Board board);
void renderPellets(Board & board) const;
void renderSuperPellets(Board & board) const;
static SDL_Rect targetRect(const Position & position, int pixel_increase);
void renderTexture(SDL_Texture * texture, SDL_Rect * texture_rect, SDL_Rect * target_rect) const;
};
#endif //PACMAN_GAMEWINDOW_H

1
src/InputState.cpp Normal file
View file

@ -0,0 +1 @@
#include "InputState.h"

13
src/InputState.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef PACMAN_INPUTSTATE_H
#define PACMAN_INPUTSTATE_H
class InputState {
public:
bool close = false;
bool up = false;
bool down = false;
bool left = false;
bool right = false;
};
#endif //PACMAN_INPUTSTATE_H

73
src/PacMan.cpp Normal file
View file

@ -0,0 +1,73 @@
#include "PacMan.h"
PacMan::PacMan() :
right_animation{right_wide, right_narrow, closed, right_narrow},
left_animation{left_wide, left_narrow, closed, left_narrow},
up_animation{up_wide, up_narrow, closed, up_narrow},
down_animation{down_wide, down_narrow, closed, down_narrow} {
}
SDL_Rect PacMan::currentSprite() const {
switch (direction) {
case Direction::NONE: return closed;
case Direction::LEFT: return left_animation[animation_position];
case Direction::RIGHT: return right_animation[animation_position];
case Direction::UP: return up_animation[animation_position];
case Direction::DOWN: return down_animation[animation_position];
}
}
Position PacMan::currentPosition() const {
return pos;
}
void PacMan::update(std::chrono::milliseconds time_delta, InputState state, const Board & board) {
setDirection(state);
updateAnimationPosition(time_delta);
updateMazePosition(time_delta, board);
}
void PacMan::setDirection(const InputState & state) {
if (state.left)
direction = Direction::LEFT;
else if (state.right)
direction = Direction::RIGHT;
else if (state.up)
direction = Direction::UP;
else if (state.down)
direction = Direction::DOWN;
}
void PacMan::updateAnimationPosition(std::chrono::milliseconds time_delta) {
animation_position_delta += (time_delta.count() / 100.0);
animation_position = int(animation_position + animation_position_delta) % 4;
animation_position_delta = (animation_position_delta < 1) ? animation_position_delta : (animation_position_delta - 1);
}
void PacMan::updateMazePosition(std::chrono::milliseconds time_delta, const Board & board) {
float_t position_delta = (time_delta.count() / 128.0);
if (board.isWalkable(pos, position_delta, direction)) {
switch (direction) {
case Direction::NONE:
break;
case Direction::LEFT:
pos.x -= position_delta;
pos.y = floor(pos.y);
break;
case Direction::RIGHT:
pos.x += position_delta;
pos.y = floor(pos.y);
break;
case Direction::UP:
pos.x = floor(pos.x);
pos.y -= position_delta;
break;
case Direction::DOWN:
pos.x = floor(pos.x);
pos.y += position_delta;
break;
}
}
}

45
src/PacMan.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef PACMAN_PACMAN_H
#define PACMAN_PACMAN_H
#include "Board.h"
#include "Direction.h"
#include "InputState.h"
#include "Position.h"
#include <SDL2/SDL_rect.h>
#include <chrono>
class PacMan {
public:
PacMan();
[[nodiscard]] SDL_Rect currentSprite() const;
[[nodiscard]] Position currentPosition() const;
void update(std::chrono::milliseconds time_delta, InputState state, const Board & board);
private:
Direction direction = Direction::NONE;
Position pos = {14, 23};
const SDL_Rect right_wide = {0*32, 0, 32, 32};
const SDL_Rect right_narrow = {1*32, 0, 32, 32};
const SDL_Rect closed = {2*32, 0, 32, 32};
const SDL_Rect left_narrow = {3*32, 0, 32, 32};
const SDL_Rect left_wide = {4*32, 0, 32, 32};
const SDL_Rect up_wide = {5*32, 0, 32, 32};
const SDL_Rect up_narrow = {6*32, 0, 32, 32};
const SDL_Rect down_wide = {7*32, 0, 32, 32};
const SDL_Rect down_narrow = {8*32, 0, 32, 32};
const SDL_Rect right_animation[4];
const SDL_Rect left_animation[4];
const SDL_Rect up_animation[4];
const SDL_Rect down_animation[4];
uint8_t animation_position = 0;
float_t animation_position_delta = 0.0;
void setDirection(const InputState & state);
void updateAnimationPosition(std::chrono::milliseconds time_delta);
void updateMazePosition(std::chrono::milliseconds time_delta, const Board & board);
};
#endif //PACMAN_PACMAN_H

11
src/Position.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef PACMAN_POSITION_H
#define PACMAN_POSITION_H
#include <math.h>
struct Position {
float_t x;
float_t y;
};
#endif //PACMAN_POSITION_H

7
src/main.cpp Normal file
View file

@ -0,0 +1,7 @@
#include "Game.h"
extern "C" int main([[maybe_unused]] int argc, [[maybe_unused]] char * argv[]) {
Game game;
game.run();
return 0;
}