From a408a43cd105b89a8d44292e2ef69802a5660497 Mon Sep 17 00:00:00 2001 From: Stephen Enders Date: Sat, 23 Jan 2021 11:52:32 -0500 Subject: Move source files to src folder We'll be making a few source files it'll be useful to have them organized at least somewhat from our non-src files --- CMakeLists.txt | 6 +- helper.cpp | 265 ------------------------------------------ helper.hpp | 104 ----------------- random.cpp | 27 ----- random.hpp | 19 --- reformat | 2 +- src/helper.cpp | 265 ++++++++++++++++++++++++++++++++++++++++++ src/helper.hpp | 104 +++++++++++++++++ src/random.cpp | 27 +++++ src/random.hpp | 19 +++ src/timedLatch.cpp | 38 ++++++ src/timedLatch.hpp | 22 ++++ src/ur.cpp | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++ timedLatch.cpp | 38 ------ timedLatch.hpp | 22 ---- ur.cpp | 334 ----------------------------------------------------- 16 files changed, 815 insertions(+), 811 deletions(-) delete mode 100644 helper.cpp delete mode 100644 helper.hpp delete mode 100644 random.cpp delete mode 100644 random.hpp create mode 100644 src/helper.cpp create mode 100644 src/helper.hpp create mode 100644 src/random.cpp create mode 100644 src/random.hpp create mode 100644 src/timedLatch.cpp create mode 100644 src/timedLatch.hpp create mode 100644 src/ur.cpp delete mode 100644 timedLatch.cpp delete mode 100644 timedLatch.hpp delete mode 100644 ur.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 683ead2..9aa3965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,11 @@ set(EXECUTABLE_NAME ur) set(SFML_LIBRARIES sfml-system sfml-window sfml-graphics) find_package(SFML 2.5 REQUIRED COMPONENTS system window graphics) -add_executable(${EXECUTABLE_NAME} ur.cpp helper.cpp timedLatch.cpp random.cpp) +add_executable(${EXECUTABLE_NAME} + src/ur.cpp + src/helper.cpp + src/timedLatch.cpp + src/random.cpp) target_link_libraries(${EXECUTABLE_NAME} ${SFML_LIBRARIES}) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/helper.cpp b/helper.cpp deleted file mode 100644 index 8d6f3ce..0000000 --- a/helper.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include "helper.hpp" -#include - -std::shared_ptr> -loadTextures(const char* path) -{ - int sprite_width = SPRITE_SIZE, sprite_height = SPRITE_SIZE; - sf::Image textureAtlas; - if (!textureAtlas.loadFromFile(path)) { - std::cerr << "Unable to load textures from file: " << path << std::endl; - throw std::runtime_error("Unable to load spritesheet"); - } - - textureAtlas.createMaskFromColor(GLOBAL_MASK); - auto imageSize = textureAtlas.getSize(); - - auto textures = std::make_shared>(); - - for (int y = 0; y < imageSize.y; y += sprite_height) { - for (int x = 0; x < imageSize.x; x += sprite_width) { - sf::Texture t; - t.loadFromImage(textureAtlas, - sf::IntRect(x, y, sprite_width, sprite_height)); - textures->push_back(t); - } - } - return textures; -} - -// increment through the textures -inline int -next(int* p, int max) -{ - int i = *p; - (*p) = (i + 1) % max; - return i; -} - -std::shared_ptr> -createBoard(std::shared_ptr> textures) -{ - auto sprites = std::make_shared>(); - sf::Texture& star_texture = (*textures)[STAR_TILE]; - int blank_idx = 0; - int sp_idx = 0; - // p1 pieces - // p1 star - { - sf::Sprite s; - s.setTexture(star_texture); - s.setPosition(pos(3, 5)); - sprites->push_back(s); - } - // p1 start - for (int i = 0; i < 3; i++) { - sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]]; - sf::Sprite s; - s.setTexture(t); - s.setPosition(pos(4 + i, 5)); - sprites->push_back(s); - } - // p1 end - { - sf::Sprite goal; - goal.setTexture((*textures)[P1_END]); - goal.setPosition(pos(8, 5)); - sprites->push_back(goal); - - sf::Sprite end_star; - end_star.setTexture(star_texture); - end_star.setPosition(pos(9, 5)); - sprites->push_back(end_star); - - sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]]; - sf::Sprite s; - s.setTexture(t); - s.setPosition(pos(10, 5)); - sprites->push_back(s); - } - // center pieces - for (int i = 0; i < 8; i++) { - sf::Sprite s; - if (i == 3) { - s.setTexture(star_texture); - } else { - sf::Texture& t = (*textures)[BLANK_TILES[next(&blank_idx, 3)]]; - s.setTexture(t); - } - s.setPosition(pos(3 + i, 4)); - sprites->push_back(s); - } - // p2 pieces - // p2 star - { - sf::Sprite s; - s.setTexture(star_texture); - s.setPosition(pos(3, 3)); - sprites->push_back(s); - } - // p2 start - for (int i = 0; i < 3; i++) { - sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]]; - sf::Sprite s; - s.setTexture(t); - s.setPosition(pos(4 + i, 3)); - sprites->push_back(s); - } - // p2 end - { - sf::Sprite goal; - goal.setTexture((*textures)[P2_END]); - goal.setPosition(pos(8, 3)); - sprites->push_back(goal); - - sf::Sprite end_star; - end_star.setTexture(star_texture); - end_star.setPosition(pos(9, 3)); - sprites->push_back(end_star); - - sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]]; - sf::Sprite end_tile; - end_tile.setTexture(t); - end_tile.setPosition(pos(10, 3)); - sprites->push_back(end_tile); - } - - return sprites; -} - -sf::Font -loadFont() -{ - sf::Font font; - if (!font.loadFromFile("./res/DejaVuSansMono.ttf")) { - std::cerr << "Unable to load font" << std::endl; - throw std::runtime_error("Unable to load font"); - } - return font; -} - -std::shared_ptr -createPiece(int id, sf::Texture& texture) -{ - - sf::Sprite s(texture); - auto p = std::make_shared(); - p->id = id; - p->sprite = s; - - return p; -} - -std::shared_ptr -createPlayer(sf::Texture& texture) -{ - std::shared_ptr player = std::make_shared(); - player->score = 0; - player->pieces = std::make_shared>(); - for (int i = 0; i < NUM_PIECES; i++) { - player->pieces->push_back(*createPiece(i + 1, texture)); - } - - return player; -} - -std::shared_ptr> -createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture) -{ - auto dice = std::make_shared>(); - - // create dice, even 0 odds 1 - // there are 8 dice results int total - // 4 potential 0s - // 4 potential 1s - // The dice will be rendered in pairs - // [0, 1] will be the left most die - // [2, 3] will be the second - // ... and so on - // Since a die can only have 2 results (0 or 1) - // To simplify how we will be placing them, the results of the roll - // will dictate which value each die gets - for (int i = 0; i < 8; i++) { - if (i % 2 == 0) { - sf::Sprite s; - s.setTexture(die0Texture); - struct dice_t die = { 0, true, s }; - dice->push_back(die); - } else { - sf::Sprite s; - s.setTexture(die1Texture); - struct dice_t die = { 1, false, s }; - dice->push_back(die); - } - } - - return dice; -} - -std::shared_ptr> -createRollSprites(sf::Texture& t1, sf::Texture& t2) -{ - auto sprites = std::make_shared>(); - - sprites->push_back(sf::Sprite(t1)); - sprites->push_back(sf::Sprite(t2)); - - return sprites; -} - -void -makeNum(sf::Sprite* sprite_ptr, - int num, - std::shared_ptr> textures) -{ - sf::Texture& t = (*textures)[NUMS_TILES[num]]; - sprite_ptr->setTexture(t); -}; - -bool -clickedPiece(sf::Vector2i mousePosition, struct piece_t* piece) -{ - return piece->sprite.getGlobalBounds().contains(mousePosition.x, - mousePosition.y); -} - -bool -canMovePiece(struct piece_t* piece, - int roll, - std::shared_ptr> myPieces, - std::shared_ptr> enemyPieces) -{ - int next = piece->position + roll; - - // rolled passed the exit - if (next > EXIT_SPACE) { - return false; - } - - // colliding with another piece - for (struct piece_t& p : (*myPieces)) { - // cannot move onto your own piece - if (p.id != piece->id && p.position == next) { - return false; - } - } - - // can't attack in safe square - for (struct piece_t& p : (*enemyPieces)) { - // cannot move onto a protected enemy piece - if (next == SAFE_SPACE && p.position == SAFE_SPACE) { - return false; - } - } - - return true; -} - -// This function takes in an row and col we want to put the sprite in -// and translate it to a real position in the view -// This is because we've ZOOMed in an that adjusts the entire view. -sf::Vector2f -pos(float c, float r) -{ - return { c * SPRITE_SIZE, r * SPRITE_SIZE }; -} diff --git a/helper.hpp b/helper.hpp deleted file mode 100644 index 3e7ffbb..0000000 --- a/helper.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef UR_HELPER_H -#define UR_HELPER_H - -#include -#include -#include - -// BOARD LAYOUT [0, 1, 2, 3](start) [4,5,6,7,8,9,10,11](middle), [12,13](end) - -static const unsigned int SPRITE_SIZE = 16; -static const unsigned int NUM_PIECES = 7; -static const unsigned int SAFE_SPACE = 7; // 0-indexed -static const unsigned int EXIT_SPACE = 14; // final space + 1 -static const float ZOOM = 0.5f; -static const float SPRITE_ROWS = 9.f; -static const float SPRITE_COLS = 14.f; -static const float SCR_W = SPRITE_SIZE / ZOOM * SPRITE_COLS / ZOOM; -static const float SCR_H = SPRITE_SIZE / ZOOM * SPRITE_ROWS / ZOOM; -static const int P1_PIECE = 19; -static const int P2_PIECE = 18; -static const int P1_BOARD_TILES[2] = { 0, 1 }; -static const int P2_BOARD_TILES[2] = { 2, 3 }; -static const int STAR_TILE = 4; -static const int BLANK_TILES[3] = { 5, 6, 7 }; -static const int P1_END = 22; -static const int P2_END = 23; -static const int DIE_0 = 17; -static const int DIE_1 = 16; -static const int NUMS_TILES[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -static const int ROLL_TILES[2] = { 20, 21 }; - -static const char* TITLE = "Royal Game of Ur"; -static const sf::Color GLOBAL_MASK(255, 0, 255, 255); - -enum GameState -{ - WAITING, - ROLLING, - PLACING, - GAME_OVER -}; - -struct piece_t -{ - int id; - int position; - sf::Sprite sprite; -}; - -struct player_t -{ - int score; - std::shared_ptr> pieces; -}; - -struct dice_t -{ - int value; - bool show; - sf::Sprite sprite; -}; - -std::shared_ptr> -loadTextures(const char* path); - -std::shared_ptr> -createBoard(std::shared_ptr> textures); - -sf::Font -loadFont(); - -std::shared_ptr -createPlayer(sf::Texture& pieceTexture); - -std::shared_ptr -createPiece(int id, sf::Texture& texture); - -std::shared_ptr> -createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture); - -std::shared_ptr> -createRollSprites(sf::Texture& t1, sf::Texture& t2); - -void -makeNum(sf::Sprite* sprite_ptr, - int num, - std::shared_ptr> textures); - -bool -clickedPiece(sf::Vector2i mousePosition, std::shared_ptr piece); - -bool -canMovePiece(std::shared_ptr piece, - int roll, - std::shared_ptr> myPieces, - std::shared_ptr> enemyPieces); - -std::vector -getLegalMoves(std::shared_ptr activePlayer, - std::shared_ptr opponent); - -sf::Vector2f -pos(float c, float r); -#endif diff --git a/random.cpp b/random.cpp deleted file mode 100644 index e94b191..0000000 --- a/random.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "random.hpp" -#include -#include - -namespace ur { - -Random::Random(int min, int max) -{ - this->min = min; - this->max = max; - // setup the random stuff - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - this->engine = std::default_random_engine(seed); - - // setup distribution - float range = float(max - min); - this->distribution = - std::normal_distribution(range / 2.f, range / 4.f); -} - -int -Random::next() -{ - return std::round(this->distribution(this->engine)); -} - -} diff --git a/random.hpp b/random.hpp deleted file mode 100644 index e74267a..0000000 --- a/random.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef UR_RANDOM_H -#define UR_RANDOM_H - -#include -namespace ur { -class Random -{ -public: - Random(int min, int max); - int next(); - -private: - int min; - int max; - std::default_random_engine engine; - std::normal_distribution distribution; -}; -} -#endif diff --git a/reformat b/reformat index 64a1a59..b5c76cd 100755 --- a/reformat +++ b/reformat @@ -1 +1 @@ -clang-format -i --style=Mozilla *.*pp +clang-format -i --style=Mozilla src/*.*pp diff --git a/src/helper.cpp b/src/helper.cpp new file mode 100644 index 0000000..8d6f3ce --- /dev/null +++ b/src/helper.cpp @@ -0,0 +1,265 @@ +#include "helper.hpp" +#include + +std::shared_ptr> +loadTextures(const char* path) +{ + int sprite_width = SPRITE_SIZE, sprite_height = SPRITE_SIZE; + sf::Image textureAtlas; + if (!textureAtlas.loadFromFile(path)) { + std::cerr << "Unable to load textures from file: " << path << std::endl; + throw std::runtime_error("Unable to load spritesheet"); + } + + textureAtlas.createMaskFromColor(GLOBAL_MASK); + auto imageSize = textureAtlas.getSize(); + + auto textures = std::make_shared>(); + + for (int y = 0; y < imageSize.y; y += sprite_height) { + for (int x = 0; x < imageSize.x; x += sprite_width) { + sf::Texture t; + t.loadFromImage(textureAtlas, + sf::IntRect(x, y, sprite_width, sprite_height)); + textures->push_back(t); + } + } + return textures; +} + +// increment through the textures +inline int +next(int* p, int max) +{ + int i = *p; + (*p) = (i + 1) % max; + return i; +} + +std::shared_ptr> +createBoard(std::shared_ptr> textures) +{ + auto sprites = std::make_shared>(); + sf::Texture& star_texture = (*textures)[STAR_TILE]; + int blank_idx = 0; + int sp_idx = 0; + // p1 pieces + // p1 star + { + sf::Sprite s; + s.setTexture(star_texture); + s.setPosition(pos(3, 5)); + sprites->push_back(s); + } + // p1 start + for (int i = 0; i < 3; i++) { + sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]]; + sf::Sprite s; + s.setTexture(t); + s.setPosition(pos(4 + i, 5)); + sprites->push_back(s); + } + // p1 end + { + sf::Sprite goal; + goal.setTexture((*textures)[P1_END]); + goal.setPosition(pos(8, 5)); + sprites->push_back(goal); + + sf::Sprite end_star; + end_star.setTexture(star_texture); + end_star.setPosition(pos(9, 5)); + sprites->push_back(end_star); + + sf::Texture& t = (*textures)[P1_BOARD_TILES[next(&sp_idx, 2)]]; + sf::Sprite s; + s.setTexture(t); + s.setPosition(pos(10, 5)); + sprites->push_back(s); + } + // center pieces + for (int i = 0; i < 8; i++) { + sf::Sprite s; + if (i == 3) { + s.setTexture(star_texture); + } else { + sf::Texture& t = (*textures)[BLANK_TILES[next(&blank_idx, 3)]]; + s.setTexture(t); + } + s.setPosition(pos(3 + i, 4)); + sprites->push_back(s); + } + // p2 pieces + // p2 star + { + sf::Sprite s; + s.setTexture(star_texture); + s.setPosition(pos(3, 3)); + sprites->push_back(s); + } + // p2 start + for (int i = 0; i < 3; i++) { + sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]]; + sf::Sprite s; + s.setTexture(t); + s.setPosition(pos(4 + i, 3)); + sprites->push_back(s); + } + // p2 end + { + sf::Sprite goal; + goal.setTexture((*textures)[P2_END]); + goal.setPosition(pos(8, 3)); + sprites->push_back(goal); + + sf::Sprite end_star; + end_star.setTexture(star_texture); + end_star.setPosition(pos(9, 3)); + sprites->push_back(end_star); + + sf::Texture& t = (*textures)[P2_BOARD_TILES[next(&sp_idx, 2)]]; + sf::Sprite end_tile; + end_tile.setTexture(t); + end_tile.setPosition(pos(10, 3)); + sprites->push_back(end_tile); + } + + return sprites; +} + +sf::Font +loadFont() +{ + sf::Font font; + if (!font.loadFromFile("./res/DejaVuSansMono.ttf")) { + std::cerr << "Unable to load font" << std::endl; + throw std::runtime_error("Unable to load font"); + } + return font; +} + +std::shared_ptr +createPiece(int id, sf::Texture& texture) +{ + + sf::Sprite s(texture); + auto p = std::make_shared(); + p->id = id; + p->sprite = s; + + return p; +} + +std::shared_ptr +createPlayer(sf::Texture& texture) +{ + std::shared_ptr player = std::make_shared(); + player->score = 0; + player->pieces = std::make_shared>(); + for (int i = 0; i < NUM_PIECES; i++) { + player->pieces->push_back(*createPiece(i + 1, texture)); + } + + return player; +} + +std::shared_ptr> +createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture) +{ + auto dice = std::make_shared>(); + + // create dice, even 0 odds 1 + // there are 8 dice results int total + // 4 potential 0s + // 4 potential 1s + // The dice will be rendered in pairs + // [0, 1] will be the left most die + // [2, 3] will be the second + // ... and so on + // Since a die can only have 2 results (0 or 1) + // To simplify how we will be placing them, the results of the roll + // will dictate which value each die gets + for (int i = 0; i < 8; i++) { + if (i % 2 == 0) { + sf::Sprite s; + s.setTexture(die0Texture); + struct dice_t die = { 0, true, s }; + dice->push_back(die); + } else { + sf::Sprite s; + s.setTexture(die1Texture); + struct dice_t die = { 1, false, s }; + dice->push_back(die); + } + } + + return dice; +} + +std::shared_ptr> +createRollSprites(sf::Texture& t1, sf::Texture& t2) +{ + auto sprites = std::make_shared>(); + + sprites->push_back(sf::Sprite(t1)); + sprites->push_back(sf::Sprite(t2)); + + return sprites; +} + +void +makeNum(sf::Sprite* sprite_ptr, + int num, + std::shared_ptr> textures) +{ + sf::Texture& t = (*textures)[NUMS_TILES[num]]; + sprite_ptr->setTexture(t); +}; + +bool +clickedPiece(sf::Vector2i mousePosition, struct piece_t* piece) +{ + return piece->sprite.getGlobalBounds().contains(mousePosition.x, + mousePosition.y); +} + +bool +canMovePiece(struct piece_t* piece, + int roll, + std::shared_ptr> myPieces, + std::shared_ptr> enemyPieces) +{ + int next = piece->position + roll; + + // rolled passed the exit + if (next > EXIT_SPACE) { + return false; + } + + // colliding with another piece + for (struct piece_t& p : (*myPieces)) { + // cannot move onto your own piece + if (p.id != piece->id && p.position == next) { + return false; + } + } + + // can't attack in safe square + for (struct piece_t& p : (*enemyPieces)) { + // cannot move onto a protected enemy piece + if (next == SAFE_SPACE && p.position == SAFE_SPACE) { + return false; + } + } + + return true; +} + +// This function takes in an row and col we want to put the sprite in +// and translate it to a real position in the view +// This is because we've ZOOMed in an that adjusts the entire view. +sf::Vector2f +pos(float c, float r) +{ + return { c * SPRITE_SIZE, r * SPRITE_SIZE }; +} diff --git a/src/helper.hpp b/src/helper.hpp new file mode 100644 index 0000000..3e7ffbb --- /dev/null +++ b/src/helper.hpp @@ -0,0 +1,104 @@ +#ifndef UR_HELPER_H +#define UR_HELPER_H + +#include +#include +#include + +// BOARD LAYOUT [0, 1, 2, 3](start) [4,5,6,7,8,9,10,11](middle), [12,13](end) + +static const unsigned int SPRITE_SIZE = 16; +static const unsigned int NUM_PIECES = 7; +static const unsigned int SAFE_SPACE = 7; // 0-indexed +static const unsigned int EXIT_SPACE = 14; // final space + 1 +static const float ZOOM = 0.5f; +static const float SPRITE_ROWS = 9.f; +static const float SPRITE_COLS = 14.f; +static const float SCR_W = SPRITE_SIZE / ZOOM * SPRITE_COLS / ZOOM; +static const float SCR_H = SPRITE_SIZE / ZOOM * SPRITE_ROWS / ZOOM; +static const int P1_PIECE = 19; +static const int P2_PIECE = 18; +static const int P1_BOARD_TILES[2] = { 0, 1 }; +static const int P2_BOARD_TILES[2] = { 2, 3 }; +static const int STAR_TILE = 4; +static const int BLANK_TILES[3] = { 5, 6, 7 }; +static const int P1_END = 22; +static const int P2_END = 23; +static const int DIE_0 = 17; +static const int DIE_1 = 16; +static const int NUMS_TILES[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; +static const int ROLL_TILES[2] = { 20, 21 }; + +static const char* TITLE = "Royal Game of Ur"; +static const sf::Color GLOBAL_MASK(255, 0, 255, 255); + +enum GameState +{ + WAITING, + ROLLING, + PLACING, + GAME_OVER +}; + +struct piece_t +{ + int id; + int position; + sf::Sprite sprite; +}; + +struct player_t +{ + int score; + std::shared_ptr> pieces; +}; + +struct dice_t +{ + int value; + bool show; + sf::Sprite sprite; +}; + +std::shared_ptr> +loadTextures(const char* path); + +std::shared_ptr> +createBoard(std::shared_ptr> textures); + +sf::Font +loadFont(); + +std::shared_ptr +createPlayer(sf::Texture& pieceTexture); + +std::shared_ptr +createPiece(int id, sf::Texture& texture); + +std::shared_ptr> +createAllDice(sf::Texture& die0Texture, sf::Texture& die1Texture); + +std::shared_ptr> +createRollSprites(sf::Texture& t1, sf::Texture& t2); + +void +makeNum(sf::Sprite* sprite_ptr, + int num, + std::shared_ptr> textures); + +bool +clickedPiece(sf::Vector2i mousePosition, std::shared_ptr piece); + +bool +canMovePiece(std::shared_ptr piece, + int roll, + std::shared_ptr> myPieces, + std::shared_ptr> enemyPieces); + +std::vector +getLegalMoves(std::shared_ptr activePlayer, + std::shared_ptr opponent); + +sf::Vector2f +pos(float c, float r); +#endif diff --git a/src/random.cpp b/src/random.cpp new file mode 100644 index 0000000..e94b191 --- /dev/null +++ b/src/random.cpp @@ -0,0 +1,27 @@ +#include "random.hpp" +#include +#include + +namespace ur { + +Random::Random(int min, int max) +{ + this->min = min; + this->max = max; + // setup the random stuff + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + this->engine = std::default_random_engine(seed); + + // setup distribution + float range = float(max - min); + this->distribution = + std::normal_distribution(range / 2.f, range / 4.f); +} + +int +Random::next() +{ + return std::round(this->distribution(this->engine)); +} + +} diff --git a/src/random.hpp b/src/random.hpp new file mode 100644 index 0000000..e74267a --- /dev/null +++ b/src/random.hpp @@ -0,0 +1,19 @@ +#ifndef UR_RANDOM_H +#define UR_RANDOM_H + +#include +namespace ur { +class Random +{ +public: + Random(int min, int max); + int next(); + +private: + int min; + int max; + std::default_random_engine engine; + std::normal_distribution distribution; +}; +} +#endif diff --git a/src/timedLatch.cpp b/src/timedLatch.cpp new file mode 100644 index 0000000..66714a5 --- /dev/null +++ b/src/timedLatch.cpp @@ -0,0 +1,38 @@ +#include "timedLatch.hpp" + +namespace ur { + +TimedLatch::TimedLatch(sf::Time duration) +{ + this->duration = duration; + this->clock = sf::Clock(); + this->isStarted = false; +}; + +void +TimedLatch::start() +{ + this->clock.restart(); + this->isStarted = true; +}; + +bool +TimedLatch::is_running() +{ + return this->isStarted && this->clock.getElapsedTime() < duration; +}; + +bool +TimedLatch::is_completed() +{ + + return this->isStarted && this->clock.getElapsedTime() >= duration; +}; + +void +TimedLatch::reset() +{ + this->isStarted = false; +}; + +} diff --git a/src/timedLatch.hpp b/src/timedLatch.hpp new file mode 100644 index 0000000..77c7d49 --- /dev/null +++ b/src/timedLatch.hpp @@ -0,0 +1,22 @@ +#ifndef UR_TIMEDLATCH_H +#define UR_TIMEDLATCH_H +#include + +namespace ur { +class TimedLatch +{ +public: + TimedLatch(sf::Time duration); + void start(); + void reset(); + bool is_running(); + bool is_completed(); + +private: + bool isStarted; + sf::Time duration; + sf::Clock clock; // internal sfml clock to manage time +}; +} + +#endif diff --git a/src/ur.cpp b/src/ur.cpp new file mode 100644 index 0000000..dc61eb3 --- /dev/null +++ b/src/ur.cpp @@ -0,0 +1,334 @@ +#include "helper.hpp" +#include "random.hpp" +#include "timedLatch.hpp" +#include +#include +#include +#include + +const char* TEXTURE_PATH = "./res/ur.png"; +const float PAD = 32.f; +const float PIECE_PAD = 8.f; +const float TEXT_OFFSET = 8.f; +const sf::Color BG_COLOR = sf::Color(66, 47, 81, 255); +const sf::Color SEMI_TRANSPARENT = sf::Color(255, 255, 255, 128); + +ur::Random dice_rand(0, 1); // 50/50 random +GameState state = GameState::WAITING; +GameState prev_state = GameState::WAITING; +struct piece_t* grabbed_piece = nullptr; +sf::Vector2f grabbed_piece_origin; + +int turn_roll = 0; +bool mouse_left_locked = false; + +inline void +change_state(GameState next) +{ + std::cout << "GameState == " << next << std::endl; + prev_state = state; + state = next; +} + +// p1 = false, p2 = true +bool turn_tracker = false; +int rolling_frame = 0; + +inline void +next(int* i, int max) +{ + (*i) = ((*i) + 1) % max; +} + +inline void +next_turn() +{ + turn_tracker = !turn_tracker; + change_state(GameState::WAITING); +} + +inline bool +p1_turn() +{ + return !turn_tracker; +} + +inline bool +p2_turn() +{ + return turn_tracker; +} + +inline void +render_dice(sf::RenderWindow* window, + std::shared_ptr> dice, + std::shared_ptr> roll_sprites, + std::shared_ptr> textures, + sf::Sprite* roll_result, + ur::TimedLatch* animation_timer, + ur::TimedLatch* animation_frame_timer) +{ + + if (animation_timer->is_completed()) { + animation_timer->reset(); + change_state(GameState::PLACING); + int rolls[4] = { + dice_rand.next(), dice_rand.next(), dice_rand.next(), dice_rand.next() + }; + // draw roll result + for (int i = 0; i < 8; i++) { + auto& die = (*dice)[i]; + die.show = die.value == rolls[i / 2]; + } + // set roll result + for (int r : rolls) + turn_roll += r; + } + + // draw dice + int dice_r, dice_c, roll_r, roll_c; + if (p1_turn()) { + dice_r = 6; + dice_c = 11; + roll_r = dice_r + 2; + roll_c = dice_c; + } else { + dice_r = 1; + dice_c = 11; + roll_r = dice_r - 1; + roll_c = dice_c; + } + + if (state == GameState::PLACING) { + // draw roll text + makeNum(roll_result, turn_roll, textures); + window->draw(*roll_result); + } else if (state == GameState::ROLLING) { + // if completed update dice sprites + if (animation_frame_timer->is_completed()) { + // iterate over each pair of dice sprites + // and show whichever matches the roll + for (int i = 0; i < 8; i += 2) { + int result = dice_rand.next(); + (*dice)[i].show = result == 0; + (*dice)[i + 1].show = result == 1; + } + } + // make sure we're started! + // note - this should come after the completed check otherwise we'll always + // restart it + if (!animation_frame_timer->is_running()) { + animation_frame_timer->start(); + } + + } else { + // draw initial values + // draw the 0s + int c = dice_c, r = dice_r; + for (int i = 0; i < 8; i += 2) { + auto& die = (*dice)[i]; + die.sprite.setPosition(pos(c++, r)); + window->draw(die.sprite); + if (i == 2) { + c = dice_c; + r += 1; + } + } + } + + int c = dice_c, r = dice_r; + int i = 0; + for (auto& die : (*dice)) { + if (die.show) { + die.sprite.setPosition(pos(c++, r)); + window->draw(die.sprite); + if (++i == 2) { + c = dice_c; + r += 1; + } + } + } + c = roll_c, r = roll_r; + for (auto& s : (*roll_sprites)) { + s.setPosition(pos(c++, r)); + } +} + +int +main() +{ + const std::shared_ptr> textures = + loadTextures(TEXTURE_PATH); + + const std::shared_ptr> board = createBoard(textures); + + const std::shared_ptr p1 = + createPlayer((*textures)[P1_PIECE]); + + const std::shared_ptr p2 = + createPlayer((*textures)[P2_PIECE]); + + const std::shared_ptr> roll_sprites = + createRollSprites((*textures)[ROLL_TILES[0]], (*textures)[ROLL_TILES[1]]); + + const std::shared_ptr> dice = + createAllDice((*textures)[DIE_0], (*textures)[DIE_1]); + + sf::Sprite p1Score; + p1Score.setPosition(pos(0, SPRITE_ROWS - 1)); + makeNum(&p1Score, 0, textures); + + sf::Sprite p2Score; + p2Score.setPosition(pos(0, 0)); + makeNum(&p2Score, 0, textures); + + // init piece positions + int p_num = (SPRITE_COLS / 2) - (p1->pieces->size() / 2) - 1; + for (auto& p : *(p1->pieces)) { + p.sprite.setPosition(pos(p_num++, SPRITE_ROWS - 1)); + } + + p_num = (SPRITE_COLS / 2) - (p2->pieces->size() / 2) - 1; + for (auto& p : *(p2->pieces)) { + p.sprite.setPosition(pos(p_num++, 0)); + } + + sf::Sprite roll_result; + roll_result.setPosition(pos(12, 4)); + + sf::RenderWindow window(sf::VideoMode(SCR_W, SCR_H), TITLE); + window.setFramerateLimit(60); + window.setVerticalSyncEnabled(true); + + sf::View view(window.getDefaultView()); + view.zoom(ZOOM); + view.setSize(view.getSize() * ZOOM); + view.setCenter(view.getSize() / 2.f); + + ur::TimedLatch rolling_animation_timer(sf::seconds(3)); + ur::TimedLatch rolling_animation_frame_pause_timer(sf::milliseconds(100)); + + while (window.isOpen()) { + + sf::Event event; + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed || + sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) { + window.close(); + } + + if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && + !mouse_left_locked) { + mouse_left_locked = true; + // check rolling button click + window.setView(view); + auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); + + // was roll clicked + if (state == GameState::WAITING) { + for (auto& s : (*roll_sprites)) { + // zoom sprite bounds + if (s.getGlobalBounds().contains(mPos)) { + std::cout << "Roll!" << std::endl; + // setup for rolling + rolling_animation_timer.start(); + change_state(GameState::ROLLING); + for (auto& rs : (*roll_sprites)) { + rs.setColor(SEMI_TRANSPARENT); + } + for (int i = 0; i < 8; i++) { + (*dice)[i].show = i % 2 == 0; // only show the 0s + } + break; + } + } + } else if (state == GameState::PLACING) { + // is a piece being clicked + std::shared_ptr> pieces; + if (p1_turn()) { + pieces = p1->pieces; + } else { + pieces = p2->pieces; + } + + for (auto& p : (*pieces)) { + if (p.sprite.getGlobalBounds().contains(mPos)) { + grabbed_piece = &p; + grabbed_piece_origin = grabbed_piece->sprite.getPosition(); + break; + } + } + } + window.setView(window.getDefaultView()); // reset back to main view + } else if (!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { + mouse_left_locked = false; + if (state == GameState::PLACING && grabbed_piece != nullptr) { + // did the piece drop into place + bool in_place = false; + sf::FloatRect intersect; + for (auto& s : *(board)) { + if (s.getGlobalBounds().intersects( + grabbed_piece->sprite.getGlobalBounds(), intersect)) { + if (intersect.width > SPRITE_SIZE / 2 && + intersect.height > SPRITE_SIZE / 2) { + grabbed_piece->sprite.setPosition(s.getPosition()); + in_place = true; + break; + } + } + } + + if (in_place) { + next_turn(); + turn_roll = 0; + for (auto& s : (*roll_sprites)) { + s.setColor(sf::Color::White); + } + } else { + grabbed_piece->sprite.setPosition(grabbed_piece_origin); + } + grabbed_piece = nullptr; + } + } + } + + window.clear(BG_COLOR); + window.setView(view); + + for (auto s : *(board)) { + window.draw(s); + } + + auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); + if (grabbed_piece != nullptr) { + float x = mPos.x - (grabbed_piece->sprite.getGlobalBounds().width / 2); + float y = mPos.y - (grabbed_piece->sprite.getGlobalBounds().height / 2); + grabbed_piece->sprite.setPosition(x, y); + } + // draw unused pieces + for (auto& p : *(p1->pieces)) { + window.draw(p.sprite); + } + for (auto& p : *(p2->pieces)) { + window.draw(p.sprite); + } + + render_dice(&window, + dice, + roll_sprites, + textures, + &roll_result, + &rolling_animation_timer, + &rolling_animation_frame_pause_timer); + for (auto& s : (*roll_sprites)) { + window.draw(s); + } + + window.draw(p1Score); + window.draw(p2Score); + window.setView(window.getDefaultView()); + window.display(); + } + + return EXIT_SUCCESS; +} diff --git a/timedLatch.cpp b/timedLatch.cpp deleted file mode 100644 index 66714a5..0000000 --- a/timedLatch.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "timedLatch.hpp" - -namespace ur { - -TimedLatch::TimedLatch(sf::Time duration) -{ - this->duration = duration; - this->clock = sf::Clock(); - this->isStarted = false; -}; - -void -TimedLatch::start() -{ - this->clock.restart(); - this->isStarted = true; -}; - -bool -TimedLatch::is_running() -{ - return this->isStarted && this->clock.getElapsedTime() < duration; -}; - -bool -TimedLatch::is_completed() -{ - - return this->isStarted && this->clock.getElapsedTime() >= duration; -}; - -void -TimedLatch::reset() -{ - this->isStarted = false; -}; - -} diff --git a/timedLatch.hpp b/timedLatch.hpp deleted file mode 100644 index 77c7d49..0000000 --- a/timedLatch.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef UR_TIMEDLATCH_H -#define UR_TIMEDLATCH_H -#include - -namespace ur { -class TimedLatch -{ -public: - TimedLatch(sf::Time duration); - void start(); - void reset(); - bool is_running(); - bool is_completed(); - -private: - bool isStarted; - sf::Time duration; - sf::Clock clock; // internal sfml clock to manage time -}; -} - -#endif diff --git a/ur.cpp b/ur.cpp deleted file mode 100644 index dc61eb3..0000000 --- a/ur.cpp +++ /dev/null @@ -1,334 +0,0 @@ -#include "helper.hpp" -#include "random.hpp" -#include "timedLatch.hpp" -#include -#include -#include -#include - -const char* TEXTURE_PATH = "./res/ur.png"; -const float PAD = 32.f; -const float PIECE_PAD = 8.f; -const float TEXT_OFFSET = 8.f; -const sf::Color BG_COLOR = sf::Color(66, 47, 81, 255); -const sf::Color SEMI_TRANSPARENT = sf::Color(255, 255, 255, 128); - -ur::Random dice_rand(0, 1); // 50/50 random -GameState state = GameState::WAITING; -GameState prev_state = GameState::WAITING; -struct piece_t* grabbed_piece = nullptr; -sf::Vector2f grabbed_piece_origin; - -int turn_roll = 0; -bool mouse_left_locked = false; - -inline void -change_state(GameState next) -{ - std::cout << "GameState == " << next << std::endl; - prev_state = state; - state = next; -} - -// p1 = false, p2 = true -bool turn_tracker = false; -int rolling_frame = 0; - -inline void -next(int* i, int max) -{ - (*i) = ((*i) + 1) % max; -} - -inline void -next_turn() -{ - turn_tracker = !turn_tracker; - change_state(GameState::WAITING); -} - -inline bool -p1_turn() -{ - return !turn_tracker; -} - -inline bool -p2_turn() -{ - return turn_tracker; -} - -inline void -render_dice(sf::RenderWindow* window, - std::shared_ptr> dice, - std::shared_ptr> roll_sprites, - std::shared_ptr> textures, - sf::Sprite* roll_result, - ur::TimedLatch* animation_timer, - ur::TimedLatch* animation_frame_timer) -{ - - if (animation_timer->is_completed()) { - animation_timer->reset(); - change_state(GameState::PLACING); - int rolls[4] = { - dice_rand.next(), dice_rand.next(), dice_rand.next(), dice_rand.next() - }; - // draw roll result - for (int i = 0; i < 8; i++) { - auto& die = (*dice)[i]; - die.show = die.value == rolls[i / 2]; - } - // set roll result - for (int r : rolls) - turn_roll += r; - } - - // draw dice - int dice_r, dice_c, roll_r, roll_c; - if (p1_turn()) { - dice_r = 6; - dice_c = 11; - roll_r = dice_r + 2; - roll_c = dice_c; - } else { - dice_r = 1; - dice_c = 11; - roll_r = dice_r - 1; - roll_c = dice_c; - } - - if (state == GameState::PLACING) { - // draw roll text - makeNum(roll_result, turn_roll, textures); - window->draw(*roll_result); - } else if (state == GameState::ROLLING) { - // if completed update dice sprites - if (animation_frame_timer->is_completed()) { - // iterate over each pair of dice sprites - // and show whichever matches the roll - for (int i = 0; i < 8; i += 2) { - int result = dice_rand.next(); - (*dice)[i].show = result == 0; - (*dice)[i + 1].show = result == 1; - } - } - // make sure we're started! - // note - this should come after the completed check otherwise we'll always - // restart it - if (!animation_frame_timer->is_running()) { - animation_frame_timer->start(); - } - - } else { - // draw initial values - // draw the 0s - int c = dice_c, r = dice_r; - for (int i = 0; i < 8; i += 2) { - auto& die = (*dice)[i]; - die.sprite.setPosition(pos(c++, r)); - window->draw(die.sprite); - if (i == 2) { - c = dice_c; - r += 1; - } - } - } - - int c = dice_c, r = dice_r; - int i = 0; - for (auto& die : (*dice)) { - if (die.show) { - die.sprite.setPosition(pos(c++, r)); - window->draw(die.sprite); - if (++i == 2) { - c = dice_c; - r += 1; - } - } - } - c = roll_c, r = roll_r; - for (auto& s : (*roll_sprites)) { - s.setPosition(pos(c++, r)); - } -} - -int -main() -{ - const std::shared_ptr> textures = - loadTextures(TEXTURE_PATH); - - const std::shared_ptr> board = createBoard(textures); - - const std::shared_ptr p1 = - createPlayer((*textures)[P1_PIECE]); - - const std::shared_ptr p2 = - createPlayer((*textures)[P2_PIECE]); - - const std::shared_ptr> roll_sprites = - createRollSprites((*textures)[ROLL_TILES[0]], (*textures)[ROLL_TILES[1]]); - - const std::shared_ptr> dice = - createAllDice((*textures)[DIE_0], (*textures)[DIE_1]); - - sf::Sprite p1Score; - p1Score.setPosition(pos(0, SPRITE_ROWS - 1)); - makeNum(&p1Score, 0, textures); - - sf::Sprite p2Score; - p2Score.setPosition(pos(0, 0)); - makeNum(&p2Score, 0, textures); - - // init piece positions - int p_num = (SPRITE_COLS / 2) - (p1->pieces->size() / 2) - 1; - for (auto& p : *(p1->pieces)) { - p.sprite.setPosition(pos(p_num++, SPRITE_ROWS - 1)); - } - - p_num = (SPRITE_COLS / 2) - (p2->pieces->size() / 2) - 1; - for (auto& p : *(p2->pieces)) { - p.sprite.setPosition(pos(p_num++, 0)); - } - - sf::Sprite roll_result; - roll_result.setPosition(pos(12, 4)); - - sf::RenderWindow window(sf::VideoMode(SCR_W, SCR_H), TITLE); - window.setFramerateLimit(60); - window.setVerticalSyncEnabled(true); - - sf::View view(window.getDefaultView()); - view.zoom(ZOOM); - view.setSize(view.getSize() * ZOOM); - view.setCenter(view.getSize() / 2.f); - - ur::TimedLatch rolling_animation_timer(sf::seconds(3)); - ur::TimedLatch rolling_animation_frame_pause_timer(sf::milliseconds(100)); - - while (window.isOpen()) { - - sf::Event event; - while (window.pollEvent(event)) { - if (event.type == sf::Event::Closed || - sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) { - window.close(); - } - - if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && - !mouse_left_locked) { - mouse_left_locked = true; - // check rolling button click - window.setView(view); - auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); - - // was roll clicked - if (state == GameState::WAITING) { - for (auto& s : (*roll_sprites)) { - // zoom sprite bounds - if (s.getGlobalBounds().contains(mPos)) { - std::cout << "Roll!" << std::endl; - // setup for rolling - rolling_animation_timer.start(); - change_state(GameState::ROLLING); - for (auto& rs : (*roll_sprites)) { - rs.setColor(SEMI_TRANSPARENT); - } - for (int i = 0; i < 8; i++) { - (*dice)[i].show = i % 2 == 0; // only show the 0s - } - break; - } - } - } else if (state == GameState::PLACING) { - // is a piece being clicked - std::shared_ptr> pieces; - if (p1_turn()) { - pieces = p1->pieces; - } else { - pieces = p2->pieces; - } - - for (auto& p : (*pieces)) { - if (p.sprite.getGlobalBounds().contains(mPos)) { - grabbed_piece = &p; - grabbed_piece_origin = grabbed_piece->sprite.getPosition(); - break; - } - } - } - window.setView(window.getDefaultView()); // reset back to main view - } else if (!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { - mouse_left_locked = false; - if (state == GameState::PLACING && grabbed_piece != nullptr) { - // did the piece drop into place - bool in_place = false; - sf::FloatRect intersect; - for (auto& s : *(board)) { - if (s.getGlobalBounds().intersects( - grabbed_piece->sprite.getGlobalBounds(), intersect)) { - if (intersect.width > SPRITE_SIZE / 2 && - intersect.height > SPRITE_SIZE / 2) { - grabbed_piece->sprite.setPosition(s.getPosition()); - in_place = true; - break; - } - } - } - - if (in_place) { - next_turn(); - turn_roll = 0; - for (auto& s : (*roll_sprites)) { - s.setColor(sf::Color::White); - } - } else { - grabbed_piece->sprite.setPosition(grabbed_piece_origin); - } - grabbed_piece = nullptr; - } - } - } - - window.clear(BG_COLOR); - window.setView(view); - - for (auto s : *(board)) { - window.draw(s); - } - - auto mPos = window.mapPixelToCoords(sf::Mouse::getPosition(window)); - if (grabbed_piece != nullptr) { - float x = mPos.x - (grabbed_piece->sprite.getGlobalBounds().width / 2); - float y = mPos.y - (grabbed_piece->sprite.getGlobalBounds().height / 2); - grabbed_piece->sprite.setPosition(x, y); - } - // draw unused pieces - for (auto& p : *(p1->pieces)) { - window.draw(p.sprite); - } - for (auto& p : *(p2->pieces)) { - window.draw(p.sprite); - } - - render_dice(&window, - dice, - roll_sprites, - textures, - &roll_result, - &rolling_animation_timer, - &rolling_animation_frame_pause_timer); - for (auto& s : (*roll_sprites)) { - window.draw(s); - } - - window.draw(p1Score); - window.draw(p2Score); - window.setView(window.getDefaultView()); - window.display(); - } - - return EXIT_SUCCESS; -} -- cgit v1.2.3-54-g00ecf