From b5961b778fb23667b3428f81ed10657dc645c30c Mon Sep 17 00:00:00 2001 From: PedroBrTe <91492908+PedroBrTe@users.noreply.github.com> Date: Sun, 26 Nov 2023 20:05:50 -0300 Subject: [PATCH] Now has multiple files and better documentation --- CMakeLists.txt | 6 +- README.MD | 2 + game/PushBlocks.cpp | 246 ++++++++++++++++++++++++++++++++++++++++++ game/PushBlocks.h | 145 +++++++++++++++++++++++++ main.cpp | 258 ++++++++++---------------------------------- 5 files changed, 453 insertions(+), 204 deletions(-) create mode 100644 game/PushBlocks.cpp create mode 100644 game/PushBlocks.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dd8ad0b..f63340b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,5 +2,9 @@ cmake_minimum_required(VERSION 3.26) project(MoveChar) set(CMAKE_CXX_STANDARD 20) +set (CMAKE_CXX_FLAGS "-static-libgcc -static-libstdc++") -add_executable(MoveChar main.cpp) +add_executable(MoveChar main.cpp + game/PushBlocks.cpp + game/PushBlocks.h +) diff --git a/README.MD b/README.MD index 18dc9ce..799ace0 100644 --- a/README.MD +++ b/README.MD @@ -16,4 +16,6 @@ Q - Exit the game ## About It is just a basic game to learn c++ basics. +You can use the header file to create your own implemetation of the game. + The code for this project is pretty bad, so feel free to contribute to the project. diff --git a/game/PushBlocks.cpp b/game/PushBlocks.cpp new file mode 100644 index 0000000..81fb776 --- /dev/null +++ b/game/PushBlocks.cpp @@ -0,0 +1,246 @@ +#include "PushBlocks.h" + + +PushBlocks::PushBlocks(int max_x, int max_y) { + map_x = max_x; + map_y = max_y; +} + + + +void PushBlocks::loadGame() { + map = {}; + box_cor = {}; + finish_cor = {}; + + createMap(); + initMap(); + + loadAll(); +} + +void PushBlocks::displayMap() { + for (int line = 0; line < map_y; line++) { + for (int space = 0; space < map_x; space++) { + std::cout << map[line][space]; + } + std::cout << "\n"; + } +} + +void PushBlocks::loadAll() { + int finish_index = getFinishIndex(last_char_x, last_char_y); + + if (finish_index != -1) { + map[last_char_y][last_char_x] = finish_c; + } else { + map[last_char_y][last_char_x] = blank_c; + } + + std::vector indexBoxToErase; + + for (const std::vector &box_cord : box_cor) { + int finish_index_from_box = getFinishIndex(box_cord[0], box_cord[1]); + + if (finish_index_from_box != -1) { + int box_index = getBoxIndex(box_cord[0], box_cord[1]); + indexBoxToErase.push_back(box_index); + } else { + map[box_cord[1]][box_cord[0]] = box_c; + } + } + + for (const int &box_index : indexBoxToErase) { + box_cor.erase(box_cor.begin() + box_index); + } + + for (const std::vector &finish_cord : finish_cor) { + map[finish_cord[1]][finish_cord[0]] = finish_c; + } + + map[char_y][char_x] = char_c; + + if (box_cor.empty()) { + upLevel(); + has_win = true; + + } else { + has_win = false; + } +} + +void PushBlocks::moveUp() { + if (char_y - 1 < 0) { + return; + } + + int boxIndex = getBoxIndex(char_x, char_y - 1); + if (boxIndex != -1) { + if (box_cor[boxIndex][1] - 1 >= 0 && getBoxIndex(box_cor[boxIndex][0], box_cor[boxIndex][1] - 1) == -1) { + --box_cor[boxIndex][1]; + } else { + return; + } + } + + last_char_y = char_y; + last_char_x = char_x; + + char_y--; + loadAll(); +} + +void PushBlocks::moveDown() { + if (char_y + 1 >= map_y) { + return; + } + + int boxIndex = getBoxIndex(char_x, char_y + 1); + if (boxIndex != -1) { + if (box_cor[boxIndex][1] + 1 < map_y && getBoxIndex(box_cor[boxIndex][0], box_cor[boxIndex][1] + 1) == -1) { + ++box_cor[boxIndex][1]; + } else { + return; + } + } + + last_char_y = char_y; + last_char_x = char_x; + + char_y++; + loadAll(); +} + +void PushBlocks::moveRight() { + if (char_x + 1 >= map_x) { + return; + } + + int boxIndex = getBoxIndex(char_x + 1, char_y); + if (boxIndex != -1) { + if (box_cor[boxIndex][0] + 1 < map_x && getBoxIndex(box_cor[boxIndex][0] + 1, box_cor[boxIndex][1]) == -1) { + ++box_cor[boxIndex][0]; + } else { + return; + } + } + + last_char_y = char_y; + last_char_x = char_x; + + char_x++; + loadAll(); +} + +void PushBlocks::moveLeft() { + if (char_x - 1 < 0) { + return; + } + + int boxIndex = getBoxIndex(char_x - 1, char_y); + if (boxIndex != -1) { + if (box_cor[boxIndex][0] - 1 >= 0 && getBoxIndex(box_cor[boxIndex][0] - 1, box_cor[boxIndex][1]) == -1) { + --box_cor[boxIndex][0]; + } else { + return; + } + } + + last_char_y = char_y; + last_char_x = char_x; + + char_x--; + loadAll(); +} + +int PushBlocks::getBoxIndex(int x, int y) { + int i = 0; + for (const std::vector &box_cord : box_cor) { + if (x == box_cord[0] && y == box_cord[1]) { + return i; + } + i++; + } + return -1; +} + +int PushBlocks::getFinishIndex(int x, int y) { + int i = 0; + for (const std::vector &finish_cord : finish_cor) { + if (x == finish_cord[0] && y == finish_cord[1]) { + return i; + } + i++; + } + return -1; +} + +int PushBlocks::get_level() { + return level; +} +std::vector> PushBlocks::get_map(){ + return map; +} + +bool PushBlocks::win() { + return has_win; +} + +void PushBlocks::createMap() { + std::vector temp_x = {}; + + for (int x = 0; x < map_x; x++) { + temp_x.push_back(blank_c); + } + for (int y = 0; y < map_y; y++) { + map.push_back(temp_x); + } +} + +void PushBlocks::initMap() { + char_x = getRandom(0, map_x - 1); + char_y = getRandom(0, map_y - 1); + + last_char_x = char_x; + last_char_y = char_y; + + initBoxes(); + initFinishPositions(); +} + +void PushBlocks::initBoxes() { + for (int i = 0; i < sqrt(level) * level/4; i++) { + int box_x, box_y; + + do { + box_x = getRandom(1, map_x - 2); + box_y = getRandom(1, map_y - 2); + } while ((box_x == char_x && box_y == char_y) || (getBoxIndex(box_x, box_y) != -1)); + + box_cor.push_back({box_x, box_y}); + } +} + +void PushBlocks::initFinishPositions() { + int finish_x, finish_y; + + do { + finish_x = getRandom(0, map_x - 1); + finish_y = getRandom(0, map_y - 1); + } while ((finish_x == char_x && finish_y == char_y) || (getBoxIndex(char_x, char_y) != -1)); + + finish_cor.push_back({finish_x, finish_y}); +} + +void PushBlocks::upLevel() { + ++level; +} + +int PushBlocks::getRandom(int min, int max) { + std::random_device rd; + std::uniform_int_distribution dist(min, max); + int random_number = dist(rd); + + return random_number; +} + diff --git a/game/PushBlocks.h b/game/PushBlocks.h new file mode 100644 index 0000000..6b79db6 --- /dev/null +++ b/game/PushBlocks.h @@ -0,0 +1,145 @@ +#pragma once + +#include +#include +#include +#include +#include + +class PushBlocks { +public: + /** + * @brief Constructor for the PushBlocks class. + * @param max_x Maximum size on the x-axis of the map. + * @param max_y Maximum size on the y-axis of the map. + * Initializes the game with a custom map size. + */ + explicit PushBlocks(int max_x = 10, int max_y = 10); + + /** + * @brief Generates the map, used at the start of the game and when you want to regenerate the map without losing your level. + */ + void loadGame(); + + /** + * @brief Displays the map. + */ + void displayMap(); + + /** + * @brief Gets the objects to their positions on the map. + */ + void loadAll(); + + /** + * @brief Handles character movement upward. + */ + void moveUp(); + + /** + * @brief Handles character movement downward. + */ + void moveDown(); + + /** + * @brief Handles character movement to the right. + */ + void moveRight(); + + /** + * @brief Handles character movement to the left. + */ + void moveLeft(); + + /** + * @brief Gets the box index by its X and Y position. + * @param x position. + * @param y position. + * @return The index of the box. + */ + int getBoxIndex(int x, int y); + + /** + * @brief Gets the finish index by its X and Y position. + * @param x position. + * @param y position. + * @return The index of the finish point. + */ + int getFinishIndex(int x, int y); + + /** + * @brief Gets the current level. + * @return The current level. + */ + int get_level(); + + /** + * @brief Returns whether the user is in a win state (finished the level). + * @return True if the user won, false otherwise. + */ + bool win(); + + /** + * @brief Returns the map so you can manage it. + * @return The game map. + */ + std::vector> get_map(); + +private: + int level = 1; + + int map_x = 10; + int map_y = 10; + + std::string char_c = "😎"; + std::string box_c = "⬛"; + std::string blank_c = "⬜"; + std::string finish_c = "🟩"; + + int char_x; + int char_y; + + int last_char_x = char_x; + int last_char_y = char_y; + + bool has_win = false; + + std::vector> box_cor; + + std::vector> finish_cor; + + std::vector> map; + + /** + * @brief Creates the game map. + */ + void createMap(); + + /** + * @brief Initializes the map. + */ + void initMap(); + + /** + * @brief Initializes the box positions. + */ + void initBoxes(); + + /** + * @brief Initializes the finish positions. + */ + void initFinishPositions(); + + /** + * @brief Increase the level variable + */ + void upLevel(); + + /** + * @brief Generates a random number in the range [min, max]. + * @param min Minimum value. + * @param max Maximum value. + * @return The randomly generated number. + */ + int getRandom(int min, int max); +}; diff --git a/main.cpp b/main.cpp index b77d8cb..32e9863 100644 --- a/main.cpp +++ b/main.cpp @@ -1,234 +1,86 @@ #include -#include #include #include #include +#include "game/PushBlocks.h" -using namespace std; void winScreen(); -void printArray(vector> map, int map_x, int map_y); -void createMap(vector> * map,int map_x, int map_y, string blank_space); - -int getRandom(int min, int max); void clear(); - -int main(){ +int main() { SetConsoleOutputCP(CP_UTF8); - while (true) { - bool continue_game = true; - - char input; - - string char_s = "😎"; - string box_s = "⬛"; - string blank_s = "⬜"; - string finish_s = "🟩"; - - int map_x = 10; - int map_y = 10; - - vector> map; + PushBlocks game; + game.loadGame(); - createMap(&map, map_x, map_y, blank_s); - - // Get objects coordinates - int char_x = getRandom(0, map_x-1); - int char_y = getRandom(0, map_y-1); - - int box_x = getRandom(1, map_x-2); - int box_y = getRandom(1, map_y-2); - - int finish_x = getRandom(0, map_x-1); - int finish_y = getRandom(0, map_y-1); - - // Check if any overlap - if ((char_x==box_x)&(char_y==box_y)|((box_x==finish_x)&(box_y==finish_y))|(char_x==finish_x)&(char_y==finish_y)){ - continue_game=false; + while (true) { + if (game.win()){ + winScreen(); + game.loadGame(); } + clear(); + std::cout << "level: " << game.get_level() << "\n"; + game.displayMap(); + std::cout << "R-Recreate Q-Exit"; - map[finish_y][finish_x] = finish_s; - - while (continue_game) { - clear(); - - int last_char_x = char_x; - int last_char_y = char_y; - + char input = tolower(_getch()); - if (box_x == finish_x & box_y == finish_y) { - winScreen(); + switch (input){ + case ('w'): + game.moveUp(); + break; + case ('s'): + game.moveDown(); + break; + case ('d'): + game.moveRight(); + break; + case ('a'): + game.moveLeft(); break; - } - - - map[char_y][char_x] = char_s; - map[box_y][box_x] = box_s; - - - cout << "Y=" << char_y << " X=" << char_x << "\n"; - - printArray(map, map_x, map_y); - cout << "R-Recreate Q-Exit"; - - input = _getch(); - - switch (input) { - case 'w': - // Go up - if ((char_y - 1 < 0)) { - break; - } - - // Checks for box and try to push it, same for others cases - if (char_y - 1 == box_y & char_x == box_x) { - if (box_y - 1 >= 0) { - --box_y; - } else { - break; - } - } - - --char_y; - break; - - case 'd': - // Go right - if (char_x + 1 > map_x - 1) { - break; - } - - if (char_x + 1 == box_x & char_y == box_y) { - if (box_x < map_x - 1) { - ++box_x; - } else { - break; - } - } - - ++char_x; - break; - - case 'a': - // Go left - if ((char_x - 1 < 0)) { - break; - } - - if (char_x - 1 == box_x & char_y == box_y) { - if (box_x - 1 >= 0) { - --box_x; - } else { - break; - } - } - - --char_x; - break; - - case 's': - // Go down - if ((char_y + 1 > map_y - 1)) { - break; - } - - if (char_y + 1 == box_y & char_x == box_x) { - if (box_y < map_y - 1) { - ++box_y; - } else { - break; - } - } - - ++char_y; - break; - - case 'r': - // Reset game - continue_game = false; - break; - - case 'q': - // Exit - exit(0); - - - default: - break; - } - - // Replace finish or blank square - if (last_char_x == finish_x & last_char_y == finish_y) { - map[last_char_y][last_char_x] = finish_s; - } else { - map[last_char_y][last_char_x] = blank_s; - } - // Delay to don't span click - Sleep(50); + case ('r'): + game.loadGame(); + break; + case ('q'): + exit(0); } } } +void winScreen() { + // Print Win Screen + char input; -void winScreen(){ - while (true){ - clear(); - - cout << " \n\n\n"; - cout << " You win!!!!!"; - cout << " \n\n\n\n"; - cout << " Q-EXIT C-CONTINUE\n"; - - char input = _getch(); - - if (tolower(input) == 'q'){ - exit(0); - } else if (tolower(input) == 'c'){ - cout << "socorro.\n"; - break; - } - } -} - - + clear(); + std::cout << " \n\n\n"; + std::cout << " Next level!"; + std::cout << " \n\n\n\n"; + std::cout << " Q-EXIT C-CONTINUE\n"; -void printArray(vector> map, int map_x, int map_y){ - for (int line=0; line> * map,int map_x, int map_y, string blank_space){ - // Create the vector/map with the desired size - vector temp_x = {}; + } else if (tolower(input) == 'c') { + return; + } - for (int x=0; xpush_back(temp_x); + } while (input!='q'<<'c'); } } -int getRandom(int min, int max){ - random_device rd; - uniform_int_distribution dist(min, max); - int returned = dist(rd); - - return returned; -} - - -void clear(){ - system("cls"); -} - +void clear() { + // clear the screen + #ifdef _WIN32 + system("cls"); + #else + system("clear"); + #endif +} \ No newline at end of file