diff --git a/src/cell.cpp b/src/cell.cpp index 95de48c..401a75d 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -46,7 +46,7 @@ bool PassableCell::onMovingTo(HeroPtr &hero, LevelPtr &level) return true; } -CellPtr PassableCell::getDefaultInstance() const +CellPtr PassableCell::clone() const { return std::make_unique(); } @@ -69,7 +69,7 @@ bool WaterCell::onMovingTo(HeroPtr &hero, LevelPtr &level) return false; } -CellPtr WaterCell::getDefaultInstance() const +CellPtr WaterCell::clone() const { return std::make_unique(); } @@ -94,7 +94,7 @@ bool WallCell::onMovingTo(HeroPtr &hero, LevelPtr &level) return false; } -CellPtr WallCell::getDefaultInstance() const +CellPtr WallCell::clone() const { return std::make_unique(); } @@ -120,7 +120,7 @@ bool ChargeCell::onMovingTo(HeroPtr &hero, LevelPtr &level) return true; } -CellPtr ChargeCell::getDefaultInstance() const +CellPtr ChargeCell::clone() const { return std::make_unique(); } @@ -143,7 +143,7 @@ bool ExitCell::onMovingTo(HeroPtr &hero, LevelPtr &level) return true; } -CellPtr ExitCell::getDefaultInstance() const +CellPtr ExitCell::clone() const { return std::make_unique(); } @@ -174,7 +174,7 @@ void TeleportCell::setDestination(coordinate new_cell_row, coordinate new_cell_c new_col = new_cell_col; } -CellPtr TeleportCell::getDefaultInstance() const +CellPtr TeleportCell::clone() const { return std::make_unique(); } @@ -182,6 +182,8 @@ CellPtr TeleportCell::getDefaultInstance() const /////////////////////////////////////// +const std::vector TriggerCell::cells_to_cast { PASSABLE_CELL, WATER_CELL, WALL_CELL, EXIT_CELL }; + TriggerCell::TriggerCell(/*std::vector &&cells_to_change,*/ coordinate cell_row, coordinate cell_col, const sf::Color &color) : Cell(cell_row, cell_col, color) { @@ -194,27 +196,31 @@ TriggerCell::TriggerCell(/*std::vector &&cells_to_change,*/ coordinate TriggerCell::~TriggerCell() {} +void TriggerCell::addTarget(CellPtr &&cell) +{ + UNUSED(cell); + //cells.emplace_back(cell); +} + bool TriggerCell::onMovingTo(HeroPtr &hero, LevelPtr &level) { UNUSED(hero); - Map &map = level->mapArray(); - // We replace needed cells with the ones that the trigger provides. for (CellPtr &cell : cells) { const coordinate &row = cell->row(); const coordinate &col = cell->col(); - map[row][col].release(); - map[row][col] = std::move(cell); + level->getCellAt(row, col).release(); + level->getCellAt(row, col) = std::move(cell); } // It's an impassable object, so player can't move to here. return false; } -CellPtr TriggerCell::getDefaultInstance() const +CellPtr TriggerCell::clone() const { return std::make_unique(); } diff --git a/src/cell.h b/src/cell.h index 3228fa7..675bbbc 100644 --- a/src/cell.h +++ b/src/cell.h @@ -21,14 +21,14 @@ const sf::Color Pink = sf::Color(255, 192, 203); const sf::Color Black = sf::Color( 0, 0, 0); } -enum CELL_TYPES { +enum CELL_TYPE { PASSABLE_CELL = 0, - WATER_CELL, - WALL_CELL, - CHARGE_CELL, - EXIT_CELL, - TELEPORT_CELL, - TRIGGER_CELL, + WATER_CELL = 1, + WALL_CELL = 2, + CHARGE_CELL = 3, + EXIT_CELL = 4, + TELEPORT_CELL = 5, + TRIGGER_CELL = 6, N_CELLS }; @@ -69,7 +69,7 @@ public: /// Determine if Hero can move onto this cell or not virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) = 0; - virtual CellPtr getDefaultInstance() const = 0; + virtual CellPtr clone() const = 0; }; /////////////////////////////////////// @@ -86,7 +86,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -103,7 +103,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -120,7 +120,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -141,7 +141,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -158,7 +158,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -182,7 +182,7 @@ public: virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; /////////////////////////////////////// @@ -191,10 +191,13 @@ public: class TriggerCell final : public Cell { private: - // Vector of cells to place on map + // Vector of cells to place on map std::vector cells; public: + // Vector of cell types you can cast in to + static const std::vector cells_to_cast; + TriggerCell(//std::vector &&cells_to_change, coordinate cell_row = 0, coordinate cell_col = 0, @@ -202,9 +205,11 @@ public: virtual ~TriggerCell() override; + void addTarget(CellPtr &&cell); + virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override; - virtual CellPtr getDefaultInstance() const override; + virtual CellPtr clone() const override; }; #endif // CELL_H diff --git a/src/game.cpp b/src/game.cpp index 0e2a501..6412f9b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -100,6 +100,6 @@ void Game::onMoving(sf::Keyboard::Key &key) ////////////////////////// - if (!level->mapArray()[attempt_row][attempt_col]->onMovingTo(hero, level)) + if (!level->getCellAt(attempt_row, attempt_col)->onMovingTo(hero, level)) hero->setPosition(initial_row, initial_col); } diff --git a/src/level.cpp b/src/level.cpp index df23285..bfdf307 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -1,103 +1,146 @@ #include "level.h" +#include #include -#include - -void Level::prepareCellInstances() -{ - default_cells[PASSABLE_CELL] = new PassableCell(); - default_cells[WATER_CELL] = new WaterCell(); - default_cells[WALL_CELL] = new WallCell(); - default_cells[CHARGE_CELL] = new ChargeCell(); - default_cells[EXIT_CELL] = new ExitCell(); - default_cells[TELEPORT_CELL] = new TeleportCell(); - default_cells[TRIGGER_CELL] = new TriggerCell(); -} - -void Level::readMap(std::ifstream &file) -{ - int i; - for (coordinate j = 0; j < map.size(); ++j) - { - for (coordinate k = 0; k < map[j].size(); ++k) - { - file >> i; - map[j][k] = default_cells[i]->getDefaultInstance(); - map[j][k]->setPosition(j, k); - } - } -} +#include +#include template // [D]erived - [B]ase -std::unique_ptr static_unique_pointer_cast (std::unique_ptr&& old) +std::unique_ptr static_unique_pointer_cast(std::unique_ptr&& old) { - return std::unique_ptr{static_cast(old.release())}; + return std::unique_ptr{static_cast(old.release())}; } -Level::Level(const std::string &map_file) +void Level::Map::init(const std::string &map_file_name) { - prepareCellInstances(); + prepareDefaultCells(); std::ifstream file; - file.open(map_file); + file.open(map_file_name); std::string cur_line; + std::istringstream sstr; + SECTION cur_section = SECTION::NONE; while (getline(file, cur_line)) { - // need fix; see std::string.compare - if (strstr(cur_line.data(), "size") != NULL) + if (map_section.find(cur_line) != map_section.end()) { - file >> level_width >> level_height; - map.resize(level_height); - for (Row &row : map) - row.resize(level_width); + cur_section = map_section[cur_line]; + continue; } - else if (strstr(cur_line.data(), "map") != NULL) - { - readMap(file); - } - else if (strstr(cur_line.data(), "teleport") != NULL) + + sstr.clear(); + sstr.str(cur_line); + switch (cur_section) { - coordinate src_row, src_col; - coordinate dest_row, dest_col; + case SECTION::SIZE: + readMapSize(sstr); + break; + + case SECTION::MAP: + readMapRow(sstr); + break; + + case SECTION::TELEPORT: + readTeleport(sstr); + break; + + case SECTION::TRIGGER: + readTrigger(sstr); + break; - file >> src_row >> src_col >> dest_row >> dest_col; - auto teleport_cell = static_unique_pointer_cast(std::move(map[src_row][src_col])); - teleport_cell->setDestination(dest_row, dest_col); - map[src_row][src_col] = std::move(teleport_cell); + default: + break; } } + + file.close(); } -Level::~Level() +void Level::Map::prepareDefaultCells() { - for (Cell *cell : default_cells) - delete cell; + default_cells[PASSABLE_CELL] = std::make_unique(); + default_cells[WATER_CELL] = std::make_unique(); + default_cells[WALL_CELL] = std::make_unique(); + default_cells[CHARGE_CELL] = std::make_unique(); + default_cells[EXIT_CELL] = std::make_unique(); + default_cells[TELEPORT_CELL] = std::make_unique(); + default_cells[TRIGGER_CELL] = std::make_unique(); } -size_t Level::width() const +void Level::Map::readMapSize(std::istringstream &sstr) { - return level_width; + sstr >> rows >> cols; + data.reserve(rows * cols); } -size_t Level::height() const +void Level::Map::readMapRow(std::istringstream &sstr) { - return level_height; + data.emplace_back(Row()); + int cell_type; + while (sstr >> cell_type) + { + data.back().emplace_back(default_cells[cell_type]->clone()); + data.back().back()->setPosition(data.size()-1, data.back().size()-1); + } } -void Level::placeBridge(coordinate row, coordinate col) +void Level::Map::readTeleport(std::istringstream &sstr) +{ + coordinate src_row, src_col; + coordinate dest_row, dest_col; + + sstr >> src_row >> src_col >> dest_row >> dest_col; + auto teleport_cell = static_unique_pointer_cast(std::move(data[src_row][src_col])); + teleport_cell->setDestination(dest_row, dest_col); + data[src_row][src_col] = std::move(teleport_cell); +} + +void Level::Map::readTrigger(std::istringstream &sstr) { - map[row][col] = std::make_unique(row, col, palette::Black); + coordinate src_row, src_col; + coordinate dest_row, dest_col; + int cell_type; + + sstr >> src_row >> src_col >> dest_row >> dest_col >> cell_type; + + if (std::find(TriggerCell::cells_to_cast.begin(), TriggerCell::cells_to_cast.end(), cell_type) == + TriggerCell::cells_to_cast.end()) + return ; + + auto trigger_cell = static_unique_pointer_cast(std::move(data[src_row][src_col])); + trigger_cell->addTarget(default_cells[cell_type]->clone()); + data[src_row][src_col] = std::move(trigger_cell); } -void Level::removeCharge(coordinate row, coordinate col) +Level::Level(const std::string &map_file_name) { - map[row][col] = std::make_unique(row, col, color_ground); + map.init(map_file_name); } -Map& Level::mapArray() +size_t Level::rows() const +{ + return map.rows; +} + +size_t Level::cols() const +{ + return map.cols; +} + +CellPtr &Level::getCellAt(coordinate row, coordinate col) +{ + return map.data[row][col]; +} + +void Level::placeBridge(coordinate row, coordinate col) +{ + map.data[row][col] = std::make_unique(row, col, palette::Black); +} + +void Level::removeCharge(coordinate row, coordinate col) { - return map; + map.data[row][col] = std::make_unique(row, col, color_ground); } sf::Color Level::defaultGroundColor() diff --git a/src/level.h b/src/level.h index fb5a0f1..fec0b9e 100644 --- a/src/level.h +++ b/src/level.h @@ -2,38 +2,74 @@ #define LEVEL_H #include -#include "cell.h" +#include -const std::string default_file_name = "test_map"; +#include "cell.h" -using Row = std::vector; -using Map = std::vector; +// Very desirable to create module for default values +const std::string default_map_file_name = "test_map"; /// Abstraction over 2D array to quickly get access to level cells class Level { private: + struct Map + { + using Row = std::vector; + using Matrix = std::vector; + + enum class SECTION + { + SIZE, + MAP, + TELEPORT, + TRIGGER, + NONE + }; + + std::map map_section = + { + { "size", SECTION::SIZE }, + { "map", SECTION::MAP }, + { "teleport", SECTION::TELEPORT }, + { "trigger", SECTION::TRIGGER }, + { "", SECTION::NONE } + }; + + Matrix data; + size_t rows, cols; + std::array default_cells; + + void init(const std::string &map_file_name = default_map_file_name); + + /// Prepare prototypes of default cells + void prepareDefaultCells(); + + /// Map file section readers + void readMapSize(std::istringstream &sstr); + void readMapRow(std::istringstream &sstr); + void readTeleport(std::istringstream &sstr); + void readTrigger(std::istringstream &sstr); + }; + Map map; sf::Color color_ground; - size_t level_width, level_height; - std::array default_cells; - - void prepareCellInstances(); - void readMap(std::ifstream &file); public: - Level(const std::string &map_file = default_file_name); - ~Level(); + Level(const std::string &map_file_name = default_map_file_name); - size_t width() const; - size_t height() const; + /// Number of map rows + size_t rows() const; + + /// Number of map columns + size_t cols() const; + + /// Get cell at position row, col + CellPtr &getCellAt(coordinate row, coordinate col); /// Place a bridge cell void placeBridge(coordinate x, coordinate y); - /// Get the 2D array of level map - Map& mapArray(); - /// Replace a charge cell with a ground cell void removeCharge(coordinate x, coordinate y); diff --git a/src/renderer.cpp b/src/renderer.cpp index 7fc89d3..a6b3f1b 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -77,8 +77,6 @@ bool Renderer::render(const LevelPtr &level, const HeroPtr &hero, sf::RenderWind if (!hero || !level) return false; - const Map &map = level->mapArray(); - painter_x = init_painter_x; painter_y = init_painter_y; horizontal_shift = 0; @@ -94,15 +92,15 @@ bool Renderer::render(const LevelPtr &level, const HeroPtr &hero, sf::RenderWind hero->position(hero_row, hero_col); // Draw map from 2D array - for (coordinate x = 0; x < level->width(); ++x) + for (coordinate c = 0; c < level->cols(); ++c) { - horizontal_shift = static_cast(level->width()) * cell_deviation; + horizontal_shift = static_cast(level->cols()) * cell_deviation; - for (coordinate y = 0; y < level->height(); ++y) + for (coordinate r = 0; r < level->rows(); ++r) { - drawCell(map[y][x], main_window); + drawCell(level->getCellAt(r, c), main_window); - if (hero_row == y && hero_col == x) + if (hero_row == r && hero_col == c) { // Draw the hero sprite brush_cell.setFillColor(palette::White); diff --git a/src/sfml-test.pro b/src/sfml-test.pro index 93c97e5..96655a6 100644 --- a/src/sfml-test.pro +++ b/src/sfml-test.pro @@ -3,7 +3,7 @@ CONFIG += c++17 CONFIG -= console app_bundle CONFIG -= qt -QMAKE_CXXFLAGS = -Wall -Werror -Wextra -Wpedantic -Wconversion -std=c++17 -O2 -g +QMAKE_CXXFLAGS = -Wall -Werror -Wextra -Wpedantic -Wconversion -std=c++17 -O0 -g SOURCES += \ cell.cpp \