diff --git a/.clang-format b/.clang-format index e34e8c0..e9e3cb2 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,7 @@ --- BasedOnStyle: Google Standard: Latest -ColumnLimit: 100 +# ColumnLimit: 80 UseTab: Always TabWidth: 8 IndentWidth: 8 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7464c00..fb0fd7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(engine) include_directories(include) set(SOURCES src/main.cpp - src/elements.cpp - src/maps.cpp + src/graphics.cpp + src/renderer.cpp src/data.cpp src/scheduler.cpp ) diff --git a/include/data.hpp b/include/data.hpp index fdf78be..00ab8f1 100644 --- a/include/data.hpp +++ b/include/data.hpp @@ -40,9 +40,10 @@ struct PlayerData const float max_vertical_acceleration { 0.0f }; }; -struct LevelData +struct MapData { const char data[MAX_ROWS][MAX_COLS + 1]; + // const char data[MAX_ROWS * MAX_COLS + 1]; }; struct TimerData @@ -53,7 +54,7 @@ struct TimerData extern const std::vector object_data; extern const std::vector entity_data; -extern const std::vector level_data; +extern const std::vector map_data; extern const std::vector timer_data; extern const PlayerData player_data; diff --git a/include/globals.hpp b/include/globals.hpp index 74a60b4..e7646f0 100644 --- a/include/globals.hpp +++ b/include/globals.hpp @@ -7,5 +7,7 @@ #define HEIGHT TILESIZE * MAX_ROWS #define FPS 60 #define GRAVITY 1 +#define FRICTION 1 +#define INVALID_NUMBER -1 #endif diff --git a/include/elements.hpp b/include/graphics.hpp similarity index 70% rename from include/elements.hpp rename to include/graphics.hpp index 70ad29e..6395b27 100644 --- a/include/elements.hpp +++ b/include/graphics.hpp @@ -13,12 +13,6 @@ #include "globals.hpp" #include "scheduler.hpp" -float -total_distance(int k); - -float const -distance_to_acceleration(int target); - struct Object; class Entity; class Player; @@ -40,7 +34,8 @@ struct Object class Entity : public Object { public: - Entity(EntityData data) : Object(data.object), _velocity(data.velocity) {}; + Entity(EntityData data) + : Object(data.object), _velocity(data.velocity) {}; void set_velocity(sf::Vector2f velocity); void set_velocity_x(int velocity); void set_velocity_y(int velocity); @@ -56,24 +51,16 @@ class Player : public Entity Player(PlayerData data) : Entity(data.entity), max_dash_acceleration(data.max_dash_acceleration), - max_vertical_acceleration(data.max_vertical_acceleration) - { - bounding_box.rect.setSize( - { total_distance(max_dash_acceleration), - data.entity.object.size.y }); - }; + max_vertical_acceleration(data.max_vertical_acceleration) {}; - Object bounding_box { object_data[1] }; float max_vertical_acceleration; float max_dash_acceleration; bool m_jumping { false }; - void handle_bounding_box(std::array, MAX_COLS>, MAX_ROWS>& tilemap); void handle_movment(std::optional dash); void handle_gravity(); - bool get_horizontal_collision( - std::array, MAX_COLS>, MAX_ROWS>& tilemap); - bool get_vertical_collision( - std::array, MAX_COLS>, MAX_ROWS>& tilemap); + void handle_collision( + std::array, MAX_COLS>, MAX_ROWS>& + tilemap); private: std::string direction { "left" }; diff --git a/include/maps.hpp b/include/renderer.hpp similarity index 63% rename from include/maps.hpp rename to include/renderer.hpp index 01563b2..4a542e7 100644 --- a/include/maps.hpp +++ b/include/renderer.hpp @@ -6,23 +6,24 @@ #include #include "data.hpp" -#include "elements.hpp" #include "globals.hpp" +#include "graphics.hpp" -class Manager +class Renderer { - public: + public: void clear(); - void load(LevelData level); + int load(MapData level); const void draw(sf::RenderWindow& window); void set_next(); void set_previous(); - void set_active(int level); - const int get_active(); - std::array, MAX_COLS>, MAX_ROWS> tilemap = {}; + void set_map(int level); + const int get_map(); + std::array, MAX_COLS>, MAX_ROWS> + tilemap = {}; - private: - int _active = 1; + private: + int _map = 1; }; #endif diff --git a/src/data.cpp b/src/data.cpp index 3d54d8c..b5732ec 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -42,7 +42,7 @@ const std::vector timer_data { }, }; -const std::vector level_data = { +const std::vector map_data = { { .data = { " ", " ", @@ -56,7 +56,7 @@ const std::vector level_data = { " ", " ", " ", - " ", + " " }}, { .data = { "1-----------------2", diff --git a/src/elements.cpp b/src/elements.cpp deleted file mode 100644 index d78b2c2..0000000 --- a/src/elements.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "elements.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "data.hpp" -#include "globals.hpp" -#ifdef __APPLE__ -#include -#include -namespace rv = ranges::views; -#else -#include -namespace rv = std::views; -#endif - -float -total_distance(int k) -{ - if (k > 3) return k + total_distance(k - 1); - else return 0; -} - -const float -distance_to_acceleration(int target) -{ - if (target <= 0) - { - return 0; - } - return roundf((-1 + sqrtf(1 + 8 * target)) / 2); -} - -void -Entity::set_velocity(sf::Vector2 velocity) -{ - _velocity = velocity; -} - -void -Entity::set_velocity_x(int velocity) -{ - _velocity.x = velocity; -} - -void -Entity::set_velocity_y(int velocity) -{ - _velocity.y = velocity; -} - -const sf::Vector2 -Entity::get_velocity() -{ - return _velocity; -} - -void -Player::handle_bounding_box( - std::array, MAX_COLS>, MAX_ROWS>& tilemap) -{ - float max_possible_dist = total_distance(player_data.max_dash_acceleration); - sf::FloatRect dash_check_box; - if (direction == "right") - { - dash_check_box = sf::FloatRect( - sf::Vector2f({ rect.getPosition().x + rect.getSize().x, rect.getPosition().y }), - sf::Vector2f({ max_possible_dist, rect.getSize().y })); - } - else - { - dash_check_box = - sf::FloatRect(sf::Vector2f({ rect.getPosition().x - max_possible_dist, - rect.getPosition().y }), - sf::Vector2f({ max_possible_dist, rect.getSize().y })); - } - - float allowed_dash_dist = max_possible_dist; - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - if (tilemap[i][j] == nullptr) continue; - sf::FloatRect tile = tilemap[i][j]->rect.getGlobalBounds(); - auto intersection = dash_check_box.findIntersection(tile); - float dist_to_tile; - if (intersection.has_value()) - { - if (direction == "right") - { - dist_to_tile = - tile.position.x - (rect.getPosition().x + rect.getSize().x); - } - else - { - dist_to_tile = - rect.getPosition().x - (tile.position.x + tile.size.x); - } - if (dist_to_tile < allowed_dash_dist) - { - allowed_dash_dist = dist_to_tile; - } - } - - if (allowed_dash_dist < 0) - { - allowed_dash_dist = 0; - } - - bounding_box.rect.setSize({ allowed_dash_dist, rect.getSize().y }); - if (direction == "right") - { - bounding_box.rect.setPosition( - { rect.getPosition().x + rect.getSize().x, rect.getPosition().y }); - } - else - { - bounding_box.rect.setPosition( - { rect.getPosition().x - allowed_dash_dist, rect.getPosition().y }); - } - max_dash_acceleration = distance_to_acceleration(allowed_dash_dist); - } -} - -void -Player::handle_movment(std::optional dash) -{ - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) - { - direction = "right"; - rect.move({ _velocity.x, 0 }); - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) - { - direction = "left"; - rect.move({ -_velocity.x, 0 }); - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && (*dash)->get_time() <= 0 && - dash.has_value()) - { - _velocity.x = max_dash_acceleration; - (*dash)->reset(); - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space) && !m_jumping && _velocity.x <= 3) - { - m_jumping = true; - _velocity.y = -max_vertical_acceleration; // push up - } -} - -void -Player::handle_gravity() -{ - if (get_velocity().x > player_data.entity.velocity.x) - { - set_velocity_x(get_velocity().x - GRAVITY); - } - else - { - set_velocity_x(get_velocity().x + GRAVITY); - } - - set_velocity_y(get_velocity().y + GRAVITY); - rect.move({ 0, get_velocity().y }); - if (get_velocity().y > ((float)TILESIZE / 2 - GRAVITY)) - { - set_velocity_y((TILESIZE / 2) - GRAVITY); - } -} - -bool -Player::get_horizontal_collision( - std::array, MAX_COLS>, MAX_ROWS>& tilemap) -{ - sf::FloatRect self = rect.getGlobalBounds(); - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - if (tilemap[i][j] == nullptr) continue; - sf::FloatRect tile = tilemap[i][j]->rect.getGlobalBounds(); - auto intersection = self.findIntersection(tile); - if (!intersection) continue; - if (intersection->size.x < intersection->size.y) - { - if (self.position.x < tile.position.x) - { - rect.setPosition( - { tile.position.x - rect.getSize().x, rect.getPosition().y }); - return true; - } - else - { - rect.setPosition( - { tile.position.x + tilemap[i][j]->rect.getSize().x, - rect.getPosition().y }); - return true; - } - } - } - return false; -} - -bool -Player::get_vertical_collision( - std::array, MAX_COLS>, MAX_ROWS>& tilemap) -{ - sf::FloatRect self = rect.getGlobalBounds(); - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - if (tilemap[i][j] == nullptr) continue; - sf::FloatRect tile = tilemap[i][j]->rect.getGlobalBounds(); - auto intersection = self.findIntersection(tile); - if (!intersection) continue; - if (intersection->position.y <= 0) continue; - if (intersection->size.y < intersection->size.x || - intersection->size.y - intersection->size.x < rect.getSize().x) - { - if (self.position.y < tile.position.y) - { - rect.setPosition( - { rect.getPosition().x, tile.position.y - rect.getSize().y }); - set_velocity_y(0); - m_jumping = false; - return true; - } - else - { - rect.setPosition( - { rect.getPosition().x, - tile.position.y + tilemap[i][j]->rect.getSize().y }); - set_velocity_y(0); - return true; - } - } - } - return false; -} diff --git a/src/graphics.cpp b/src/graphics.cpp new file mode 100644 index 0000000..8e50482 --- /dev/null +++ b/src/graphics.cpp @@ -0,0 +1,276 @@ +#include "graphics.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "data.hpp" +#include "globals.hpp" +#ifdef __APPLE__ +#include +#include +namespace rv = ranges::views; +#else +#include +namespace rv = std::views; +#endif + +void +Entity::set_velocity(sf::Vector2 velocity) +{ + _velocity = velocity; +} + +void +Entity::set_velocity_x(int velocity) +{ + _velocity.x = velocity; +} + +void +Entity::set_velocity_y(int velocity) +{ + _velocity.y = velocity; +} + +const sf::Vector2 +Entity::get_velocity() +{ + return _velocity; +} + +void +Player::handle_collision( + std::array, MAX_COLS>, MAX_ROWS>& + tilemap) +{ + float epsilon = 0.1f; + float x_entry = 1.0f; + bool x_hit = false; + + int start_x = std::max(0, (int)(rect.getPosition().x / TILESIZE) - 1); + int end_x = std::min( + MAX_COLS - 1, + (int)((rect.getPosition().x + rect.getSize().x + _velocity.x) / + TILESIZE + + 1)); + int start_y = std::max(0, (int)(rect.getPosition().y / TILESIZE) - 1); + int end_y = std::min( + MAX_ROWS - 1, + (int)((rect.getPosition().y + rect.getSize().y + _velocity.y) / + TILESIZE + + 1)); + for (int i = 0; i < MAX_ROWS; i++) + { + for (int j = 0; j < MAX_COLS; j++) + { + if (!tilemap[i][j]) continue; + bool y_overlap = + (rect.getPosition().y < + tilemap[i][j]->rect.getPosition().y + + tilemap[i][j]->rect.getSize().y) && + (rect.getPosition().y + rect.getSize().y > + tilemap[i][j]->rect.getPosition().y); + if (!y_overlap) continue; + + float dist_x_entry, dist_x_exit; + if (_velocity.x > 0) + { + dist_x_entry = + tilemap[i][j]->rect.getPosition().x - + (rect.getPosition().x + rect.getSize().x); + dist_x_exit = + (tilemap[i][j]->rect.getPosition().x + + tilemap[i][j]->rect.getSize().x) - + rect.getPosition().x; + } + else + { + dist_x_entry = + (tilemap[i][j]->rect.getPosition().x + + tilemap[i][j]->rect.getSize().x) - + rect.getPosition().x; + dist_x_exit = + tilemap[i][j]->rect.getPosition().x - + (rect.getPosition().x + rect.getSize().x); + } + + float t_x_entry = (_velocity.x == 0) + ? -INFINITY + : dist_x_entry / _velocity.x; + float t_x_exit = (_velocity.x == 0) + ? INFINITY + : dist_x_exit / _velocity.x; + + if (t_x_entry < t_x_exit && t_x_entry >= 0.0f && + t_x_entry < x_entry) + { + x_entry = t_x_entry; + x_hit = true; + } + } + } + if (x_hit) + { + rect.setPosition( + { rect.getPosition().x + (_velocity.x * x_entry), + rect.getPosition().y }); + if (_velocity.x > 0) rect.move({ -epsilon, 0 }); + else rect.move({ epsilon, 0 }); + _velocity.x = 0; + } + else + { + rect.move({ _velocity.x, 0 }); + } + + float y_entry = 1.0f; + bool y_hit = false; + + start_x = std::max(0, (int)(rect.getPosition().x / TILESIZE) - 1); + end_x = std::min( + MAX_COLS - 1, + (int)((rect.getPosition().x + rect.getSize().x) / TILESIZE) + 1); + start_y = std::max(0, (int)(rect.getPosition().y / TILESIZE) - 1); + end_y = std::min(MAX_ROWS - 1, (int)((rect.getPosition().y + + rect.getSize().y + _velocity.y) / + TILESIZE) + + 1); + + for (int i = 0; i < MAX_ROWS; i++) + { + for (int j = 0; j < MAX_COLS; j++) + { + if (!tilemap[i][j]) continue; + bool x_overlap = + (rect.getPosition().x < + tilemap[i][j]->rect.getPosition().x + + tilemap[i][j]->rect.getSize().x) && + (rect.getPosition().x + rect.getSize().x > + tilemap[i][j]->rect.getPosition().x); + if (!x_overlap) continue; + + float dist_y_entry, dist_y_exit; + if (_velocity.y > 0) + { + dist_y_entry = + tilemap[i][j]->rect.getPosition().y - + (rect.getPosition().y + rect.getSize().y); + dist_y_exit = + (tilemap[i][j]->rect.getPosition().y + + tilemap[i][j]->rect.getSize().y) - + rect.getPosition().y; + } + else + { + dist_y_entry = + (tilemap[i][j]->rect.getPosition().y + + tilemap[i][j]->rect.getSize().y) - + rect.getPosition().y; + dist_y_exit = + tilemap[i][j]->rect.getPosition().y - + (rect.getPosition().y + rect.getSize().y); + } + + float t_y_entry = (_velocity.y == 0) + ? -INFINITY + : dist_y_entry / _velocity.y; + float t_y_exit = (_velocity.y == 0) + ? INFINITY + : dist_y_exit / _velocity.y; + + if (t_y_entry < t_y_exit && t_y_entry >= 0.0f && + t_y_entry < y_entry) + { + y_entry = t_y_entry; + y_hit = true; + } + } + } + + if (y_hit) + { + rect.setPosition( + { rect.getPosition().x, + rect.getPosition().y + (_velocity.y * y_entry) }); + if (_velocity.y > 0) + { + rect.move({ 0, -epsilon }); + m_jumping = false; + } + else + { + rect.move({ 0, epsilon }); + } + _velocity.y = 0; + } + else + { + rect.move({ 0, _velocity.y }); + } +} + +void +Player::handle_movment(std::optional dash) +{ + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) + { + direction = "right"; + if (_velocity.x < player_data.entity.velocity.x) + { + _velocity.x = player_data.entity.velocity.x; + } + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) + { + direction = "left"; + if (_velocity.x > -player_data.entity.velocity.x) + { + _velocity.x = -player_data.entity.velocity.x; + } + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && + (*dash)->get_time() <= 0 && dash.has_value()) + { + float dash_dir = (direction == "right") ? 1.0f : -1.0f; + _velocity.x = max_dash_acceleration * dash_dir; + (*dash)->reset(); + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space) && + !m_jumping && _velocity.x <= 3) + { + m_jumping = true; + _velocity.y = -max_vertical_acceleration; // push up + } +} + +void +Player::handle_gravity() +{ + if (_velocity.x > 0) + { + _velocity.x -= FRICTION; + if (_velocity.x < 0) _velocity.x = 0; + } + else if (_velocity.x < 0) + { + _velocity.x += FRICTION; + if (_velocity.x > 0) _velocity.x = 0; + } + _velocity.y += GRAVITY; + float terminal_velocity = (float)TILESIZE / 2 - 1.0f; + if (_velocity.y > terminal_velocity) + { + _velocity.y = terminal_velocity; + } +} diff --git a/src/main.cpp b/src/main.cpp index dd23138..064c764 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -22,28 +23,30 @@ #endif #include "data.hpp" -#include "elements.hpp" #include "globals.hpp" -#include "maps.hpp" +#include "graphics.hpp" +#include "renderer.hpp" #include "scheduler.hpp" int main() { Scheduler scheduler; - Manager map_manager; - map_manager.load(level_data[BASE]); + Renderer renderer; + renderer.load(map_data[BASE]); std::atomic running { true }; - sf::RenderWindow window(sf::VideoMode({ WIDTH, HEIGHT }), "engine", sf::Style::Default); + sf::RenderWindow window(sf::VideoMode({ WIDTH, HEIGHT }), "engine", + sf::Style::Default); window.setFramerateLimit(FPS); Player player { player_data }; - sf::Font font("$HOME/personal/Projects/CPP/engine/assets/pixel.ttf"); + sf::Font font("../assets/pixel.ttf"); sf::Text text(font, "0, 0", 16); - text.setPosition({ WIDTH - (TILESIZE * 11.5), HEIGHT - (int)(TILESIZE / 1.5) }); + text.setPosition( + { WIDTH - (TILESIZE * 11.5), HEIGHT - (int)(TILESIZE / 1.5) }); std::jthread scheduler_thread([&] { scheduler.update(running); }); @@ -51,7 +54,8 @@ main() { window.clear(sf::Color::Black); - text.setString(std::to_string(scheduler.timers.at(0).get_time())); + text.setString( + std::to_string(scheduler.timers.at(0).get_time())); while (const std::optional event = window.pollEvent()) { if (event->is()) @@ -67,33 +71,23 @@ main() window.close(); } - if (map_manager.get_active() >= level_data.size()) - { - map_manager.set_active(DEFAULT); - map_manager.load(level_data[DEFAULT]); - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Enter) && (*scheduler.pull("Dash"))->below_or_zero()) { - map_manager.set_next(); + renderer.set_next(); (*scheduler.pull("Dash"))->reset(); } player.handle_movment(scheduler.pull("Dash")); - player.get_horizontal_collision(map_manager.tilemap); - player.handle_gravity(); - player.get_vertical_collision(map_manager.tilemap); - player.handle_bounding_box(map_manager.tilemap); + player.handle_collision(renderer.tilemap); - map_manager.draw(window); + renderer.draw(window); window.draw(player.rect); - window.draw(player.bounding_box.rect); window.draw(text); window.display(); } - map_manager.clear(); + renderer.clear(); return 0; } diff --git a/src/maps.cpp b/src/maps.cpp deleted file mode 100644 index b2f8119..0000000 --- a/src/maps.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "maps.hpp" - -#include -#include -#include - -#include "data.hpp" -#include "elements.hpp" -#include "globals.hpp" -#ifdef __APPLE__ -#include -#include -namespace rv = ranges::views; -#else -#include -namespace rv = std::views; -#endif - -void -Manager::clear() -{ - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - tilemap[i][j] = nullptr; - } -} - -const int -Manager::get_active() -{ - return _active; -} - -void -Manager::set_active(int new_level) -{ - _active = new_level; -} - -void -Manager::set_next() -{ - _active++; - clear(); - load(level_data[_active]); -} - -void -Manager::set_previous() -{ - _active--; - clear(); - load(level_data[_active]); -} - -const void -Manager::draw(sf::RenderWindow& window) -{ - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - if (tilemap[i][j] == nullptr) continue; - window.draw(tilemap[i][j]->rect); - } -} - -void -Manager::load(LevelData level) -{ - const char (*map_data)[MAX_COLS + 1] = level.data; - for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) - { - if (map_data[i][j] == ' ') continue; - if (map_data[i][j] == '0') - { - tilemap[i][j] = std::make_unique(object_data[0]); - tilemap[i][j]->rect.setPosition( - { tilemap[i][j]->rect.getPosition().x * j, - tilemap[i][j]->rect.getPosition().y * i }); - } - if (map_data[i][j] == '1' && j + 1 < MAX_COLS && map_data[i][j + 1] == '2') - { - int start = j, end = j + 1; - tilemap[i][j] = std::make_unique(object_data[0]); - tilemap[i][j]->rect.setSize( - { tilemap[i][j]->rect.getSize().x * float(end - start + 1), - tilemap[i][j]->rect.getSize().y }); - tilemap[i][j]->rect.setPosition( - { tilemap[i][j]->rect.getPosition().x * j, - tilemap[i][j]->rect.getPosition().y * i }); - } - if (map_data[i][j] == '1' && i + 1 < MAX_ROWS && map_data[i + 1][j] == '2') - { - int start = i, end = i + 1; - tilemap[i][j] = std::make_unique(object_data[0]); - tilemap[i][j]->rect.setSize( - { tilemap[i][j]->rect.getSize().x, - tilemap[i][j]->rect.getSize().y * float(end - start + 1) }); - tilemap[i][j]->rect.setPosition( - { tilemap[i][j]->rect.getPosition().x * j, - tilemap[i][j]->rect.getPosition().y * i }); - } - if (map_data[i][j] == '1' && j + 1 < MAX_COLS && map_data[i][j + 1] == '-') - { - int start = j, end = j; - while (end + 1 < MAX_COLS && map_data[i][end + 1] != '2') end++; - if (map_data[i][end + 1] == '2') end++; - tilemap[i][j] = std::make_unique(object_data[0]); - tilemap[i][j]->rect.setSize( - { tilemap[i][j]->rect.getSize().x * float(end - start + 1), - tilemap[i][j]->rect.getSize().y }); - tilemap[i][j]->rect.setPosition( - { tilemap[i][j]->rect.getPosition().x * j, - tilemap[i][j]->rect.getPosition().y * i }); - } - if (map_data[i][j] == '1' && i + 1 < MAX_ROWS && map_data[i + 1][j] == '|') - { - int start = i, end = i; - while (end + 1 < MAX_ROWS && map_data[end + 1][j] != '2') end++; - if (map_data[end + 1][j] == '2') end++; - tilemap[i][j] = std::make_unique(object_data[0]); - tilemap[i][j]->rect.setSize( - { tilemap[i][j]->rect.getSize().x, - tilemap[i][j]->rect.getSize().y * float(end - start + 1) }); - tilemap[i][j]->rect.setPosition( - { tilemap[i][j]->rect.getPosition().x * j, - tilemap[i][j]->rect.getPosition().y * i }); - } - } -} diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..27ed3ad --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,171 @@ +#include "renderer.hpp" + +#include +#include +#include + +#include "data.hpp" +#include "globals.hpp" +#include "graphics.hpp" +#ifdef __APPLE__ +#include +#include +namespace rv = ranges::views; +#else +#include +namespace rv = std::views; +#endif + +void +Renderer::clear() +{ + for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), + rv::iota(0, MAX_COLS))) + { + tilemap[i][j] = nullptr; + } +} + +const int +Renderer::get_map() +{ + return _map; +} + +void +Renderer::set_map(int new_level) +{ + _map = new_level; +} + +void +Renderer::set_next() +{ + _map++; + clear(); + if (load(map_data[_map]) == INVALID_NUMBER) + { + set_map(DEFAULT); + load(map_data[_map]); + }; +} + +void +Renderer::set_previous() +{ + _map--; + clear(); + if (load(map_data[_map]) == INVALID_NUMBER) + { + set_map(map_data.size() - 1); + load(map_data[_map]); + }; +} + +const void +Renderer::draw(sf::RenderWindow& window) +{ + for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), + rv::iota(0, MAX_COLS))) + { + if (tilemap[i][j] == nullptr) continue; + window.draw(tilemap[i][j]->rect); + } +} + +int +Renderer::load(MapData level) +{ + const char (*data)[MAX_COLS + 1]; + try + { + if (_map < map_data.size()) + { + data = level.data; + } + else + { + throw INVALID_NUMBER; + } + } + catch (int x) + { + return INVALID_NUMBER; + } + for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), + rv::iota(0, MAX_COLS))) + { + if (data[i][j] == ' ') continue; + if (data[i][j] == '0') + { + tilemap[i][j] = + std::make_unique(object_data[0]); + tilemap[i][j]->rect.setPosition( + { tilemap[i][j]->rect.getPosition().x * j, + tilemap[i][j]->rect.getPosition().y * i }); + } + if (data[i][j] == '1' && j + 1 < MAX_COLS && + data[i][j + 1] == '2') + { + int start = j, end = j + 1; + tilemap[i][j] = + std::make_unique(object_data[0]); + tilemap[i][j]->rect.setSize( + { tilemap[i][j]->rect.getSize().x * + float(end - start + 1), + tilemap[i][j]->rect.getSize().y }); + tilemap[i][j]->rect.setPosition( + { tilemap[i][j]->rect.getPosition().x * j, + tilemap[i][j]->rect.getPosition().y * i }); + } + if (data[i][j] == '1' && i + 1 < MAX_ROWS && + data[i + 1][j] == '2') + { + int start = i, end = i + 1; + tilemap[i][j] = + std::make_unique(object_data[0]); + tilemap[i][j]->rect.setSize( + { tilemap[i][j]->rect.getSize().x, + tilemap[i][j]->rect.getSize().y * + float(end - start + 1) }); + tilemap[i][j]->rect.setPosition( + { tilemap[i][j]->rect.getPosition().x * j, + tilemap[i][j]->rect.getPosition().y * i }); + } + if (data[i][j] == '1' && j + 1 < MAX_COLS && + data[i][j + 1] == '-') + { + int start = j, end = j; + while (end + 1 < MAX_COLS && data[i][end + 1] != '2') + end++; + if (data[i][end + 1] == '2') end++; + tilemap[i][j] = + std::make_unique(object_data[0]); + tilemap[i][j]->rect.setSize( + { tilemap[i][j]->rect.getSize().x * + float(end - start + 1), + tilemap[i][j]->rect.getSize().y }); + tilemap[i][j]->rect.setPosition( + { tilemap[i][j]->rect.getPosition().x * j, + tilemap[i][j]->rect.getPosition().y * i }); + } + if (data[i][j] == '1' && i + 1 < MAX_ROWS && + data[i + 1][j] == '|') + { + int start = i, end = i; + while (end + 1 < MAX_ROWS && data[end + 1][j] != '2') + end++; + if (data[end + 1][j] == '2') end++; + tilemap[i][j] = + std::make_unique(object_data[0]); + tilemap[i][j]->rect.setSize( + { tilemap[i][j]->rect.getSize().x, + tilemap[i][j]->rect.getSize().y * + float(end - start + 1) }); + tilemap[i][j]->rect.setPosition( + { tilemap[i][j]->rect.getPosition().x * j, + tilemap[i][j]->rect.getPosition().y * i }); + } + } + return 0; +}