diff --git a/CLAUDE.md b/CLAUDE.md index 72b331d..5da283a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,7 +91,15 @@ Se han renombrado las referencias de `JailDoctor's Dilemma` → `Projecte 2026` - `checkFloor` para PASSABLE: solo aterriza si `foot_y_current <= tile_top` (pies estaban por encima). - `checkFloor` para slopes: solo aterriza si `foot_y_current <= slope_y` (pies por encima de la superficie). - `isInsideAnySlope()`: si algún pie está por debajo de la superficie de cualquier slope que solape, bloquea TODOS los aterrizajes en slopes. Esto asegura que al hacer drop o saltar desde abajo, el jugador atraviesa toda la escalera de slopes sin quedarse pegado. -- **Pendiente:** tiles 5 (kill) y 6 (conveyor) no soportados aún en el nuevo motor. +- **Kill tiles (tipo 5):** implementados en `TileCollider::touchesKillTile()`. Comprueba si el rectángulo del jugador solapa algún tile KILL. Se llama en `Player::update()` después del movimiento. +- **Motor antiguo eliminado:** + - `CollisionMap` reducido a wrapper mínimo: solo contiene `collision_tile_map_`, `conveyor_belt_direction_` y `TileCollider`. + - Eliminados de `CollisionMap`: enum `Tile` antiguo, `getTile()`, `getSlopeHeight()`, todas las listas de superficies (`bottom_floors_`, `top_floors_`, etc.), todos los `check*Surfaces()`, `initializeSurfaces()`, `collect*Tiles()`, `buildHorizontalLines()`, `set*Surfaces()`. + - Eliminados de `Room`: enum `Tile`, `getTile()`, `getSlopeHeight()`, `getTileSize()`, todos los `check*()` delegados, `getSlopeAtPoint()`. + - Eliminados de `utils.hpp/cpp`: structs `LineHorizontal`, `LineVertical`, `LineDiagonal`, `Line` y todos los `checkCollision` / `normalizeLine` que los usaban. + - `TilemapRenderer`: eliminado `renderDebugCollisionSurfaces()` (pintaba líneas de superficies). Modo debug (tecla 0) ahora renderiza el collision tilemap usando `collision.gif`. + - `TilemapRenderer::setAnimatedTiles()` ahora lee del `collision_tile_map` (valor 6 = conveyor) en vez de `CollisionMap::getTile()`. +- **Pendiente:** tile 6 (conveyor) no soportado aún en el nuevo motor de Player. ### Otros - Añadidos `desktop.ini` y `Thumbs.db` al `.gitignore`. diff --git a/source/game/gameplay/collision_map.cpp b/source/game/gameplay/collision_map.cpp index b060ed4..a68ef4a 100644 --- a/source/game/gameplay/collision_map.cpp +++ b/source/game/gameplay/collision_map.cpp @@ -1,494 +1,8 @@ #include "collision_map.hpp" -#include // Para std::ranges::any_of +#include // Para std::move -#ifdef _DEBUG -#include "core/system/debug.hpp" // Para Debug -#endif -#include "utils/defines.hpp" // Para Collision - -// Constructor CollisionMap::CollisionMap(std::vector collision_tile_map, int conveyor_belt_direction) : collision_tile_map_(std::move(collision_tile_map)), conveyor_belt_direction_(conveyor_belt_direction), - tile_collider_(collision_tile_map_) { - // Inicializa todas las superficies de colisión - initializeSurfaces(); -} - -// Inicializa todas las superficies de colisión -void CollisionMap::initializeSurfaces() { - setBottomSurfaces(); - setTopSurfaces(); - setLeftSurfaces(); - setRightSurfaces(); - setLeftSlopes(); - setRightSlopes(); - setAutoSurfaces(); -} - -// Devuelve el tipo de tile que hay en ese pixel -auto CollisionMap::getTile(SDL_FPoint point) const -> Tile { - const int ROW = static_cast(point.y / TILE_SIZE); - const int COL = static_cast(point.x / TILE_SIZE); - const int POS = (ROW * MAP_WIDTH) + COL; - return getTile(POS); -} - -// Devuelve el tipo de tile que hay en ese indice (lee del collision_tile_map) -auto CollisionMap::getTile(int index) const -> Tile { - if (index < 0 || index >= static_cast(collision_tile_map_.size())) { - return Tile::EMPTY; - } - - switch (collision_tile_map_[index]) { - case 1: - return Tile::WALL; - case 2: - return Tile::PASSABLE; - case 3: - return Tile::SLOPE_L; - case 4: - return Tile::SLOPE_R; - case 5: - return Tile::KILL; - case 6: - return Tile::ANIMATED; - default: - return Tile::EMPTY; - } -} - -// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile -auto CollisionMap::getSlopeHeight(SDL_FPoint p, Tile slope) -> int { - // Calcula la base del tile - int base = ((p.y / TILE_SIZE) * TILE_SIZE) + TILE_SIZE; -#ifdef _DEBUG - Debug::get()->set("slope.BASE", std::to_string(base)); -#endif - - // Calcula cuanto se ha entrado en el tile horizontalmente - const int POS = (static_cast(p.x) % TILE_SIZE); // Esto da un valor entre 0 y 7 -#ifdef _DEBUG - Debug::get()->set("slope.POS", std::to_string(POS)); -#endif - - // Se resta a la base la cantidad de pixeles pos en funcion de la rampa - if (slope == Tile::SLOPE_R) { - base -= POS + 1; -#ifdef _DEBUG - Debug::get()->set("slope.result", "BASE_R=" + std::to_string(base)); -#endif - } else { - base -= (TILE_SIZE - POS); -#ifdef _DEBUG - Debug::get()->set("slope.result", "BASE_L=" + std::to_string(base)); -#endif - } - - return base; -} - -// === Queries de colisión === - -// Comprueba las colisiones con paredes derechas -auto CollisionMap::checkRightSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& s : right_walls_) { - if (checkCollision(s, rect)) { - return s.x; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones con paredes izquierdas -auto CollisionMap::checkLeftSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& s : left_walls_) { - if (checkCollision(s, rect)) { - return s.x; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones con techos -auto CollisionMap::checkTopSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& s : top_floors_) { - if (checkCollision(s, rect)) { - return s.y; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones punto con techos -auto CollisionMap::checkTopSurfaces(const SDL_FPoint& p) -> bool { - return std::ranges::any_of(top_floors_, [&](const auto& s) -> bool { - return checkCollision(s, p); - }); -} - -// Comprueba las colisiones con suelos -auto CollisionMap::checkBottomSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& s : bottom_floors_) { - if (checkCollision(s, rect)) { - return s.y; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones con conveyor belts -auto CollisionMap::checkAutoSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& s : conveyor_belt_floors_) { - if (checkCollision(s, rect)) { - return s.y; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones punto con conveyor belts -auto CollisionMap::checkConveyorBelts(const SDL_FPoint& p) -> bool { - return std::ranges::any_of(conveyor_belt_floors_, [&](const auto& s) -> bool { - return checkCollision(s, p); - }); -} - -// Comprueba las colisiones línea con rampas izquierdas -auto CollisionMap::checkLeftSlopes(const LineVertical& line) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& slope : left_slopes_) { - const auto P = checkCollision(slope, line); - if (P.x != -1) { - return P.y; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones punto con rampas izquierdas -auto CollisionMap::checkLeftSlopes(const SDL_FPoint& p) -> bool { - return std::ranges::any_of(left_slopes_, [&](const auto& slope) -> bool { - return checkCollision(p, slope); - }); -} - -// Comprueba las colisiones línea con rampas derechas -auto CollisionMap::checkRightSlopes(const LineVertical& line) -> int { // NOLINT(readability-convert-member-functions-to-static) - for (const auto& slope : right_slopes_) { - const auto P = checkCollision(slope, line); - if (P.x != -1) { - return P.y; - } - } - return Collision::NONE; -} - -// Comprueba las colisiones punto con rampas derechas -auto CollisionMap::checkRightSlopes(const SDL_FPoint& p) -> bool { - return std::ranges::any_of(right_slopes_, [&](const auto& slope) -> bool { - return checkCollision(p, slope); - }); -} - -// Obtiene puntero a slope en un punto (prioriza left_slopes_ sobre right_slopes_) -auto CollisionMap::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { // NOLINT(readability-convert-member-functions-to-static) - // Primero busca en rampas izquierdas - for (const auto& slope : left_slopes_) { - if (checkCollision(p, slope)) { - return &slope; - } - } - - // Luego busca en rampas derechas - for (const auto& slope : right_slopes_) { - if (checkCollision(p, slope)) { - return &slope; - } - } - - // No hay colisión con ninguna slope - return nullptr; -} - -// === Helpers para recopilar tiles === - -// Helper: recopila tiles inferiores (muros sin muro debajo) -auto CollisionMap::collectBottomTiles() -> std::vector { // NOLINT(readability-make-member-function-const) - std::vector tile; - - // Busca todos los tiles de tipo muro que no tengan debajo otro muro - // Hay que recorrer la habitación por filas (excepto los de la última fila) - for (int i = 0; i < (int)collision_tile_map_.size() - MAP_WIDTH; ++i) { - if (getTile(i) == Tile::WALL && getTile(i + MAP_WIDTH) != Tile::WALL) { - tile.push_back(i); - - // Si llega al final de la fila, introduce un separador - if (i % MAP_WIDTH == MAP_WIDTH - 1) { - tile.push_back(-1); - } - } - } - - // Añade un terminador - tile.push_back(-1); - return tile; -} - -// Helper: recopila tiles superiores (muros o pasables sin muro encima) -auto CollisionMap::collectTopTiles() -> std::vector { // NOLINT(readability-make-member-function-const) - std::vector tile; - - // Busca todos los tiles de tipo muro o pasable que no tengan encima un muro - // Hay que recorrer la habitación por filas (excepto los de la primera fila) - for (int i = MAP_WIDTH; i < (int)collision_tile_map_.size(); ++i) { - if ((getTile(i) == Tile::WALL || getTile(i) == Tile::PASSABLE) && getTile(i - MAP_WIDTH) != Tile::WALL) { - tile.push_back(i); - - // Si llega al final de la fila, introduce un separador - if (i % MAP_WIDTH == MAP_WIDTH - 1) { - tile.push_back(-1); - } - } - } - - // Añade un terminador - tile.push_back(-1); - return tile; -} - -// Helper: recopila tiles conveyor belt -auto CollisionMap::collectConveyorTiles() -> std::vector { // NOLINT(readability-make-member-function-const) - std::vector tile; - - // Busca todos los tiles de tipo conveyor - for (int i = MAP_WIDTH; i < (int)collision_tile_map_.size(); ++i) { - if (getTile(i) == Tile::ANIMATED) { - tile.push_back(i); - - // Si llega al final de la fila, introduce un separador - if (i % MAP_WIDTH == MAP_WIDTH - 1) { - tile.push_back(-1); - } - } - } - - // Añade un terminador si hay tiles - if (!tile.empty()) { - tile.push_back(-1); - } - - return tile; -} - -// Helper: construye lineas horizontales a partir de tiles consecutivos -void CollisionMap::buildHorizontalLines(const std::vector& tiles, std::vector& lines, bool is_bottom_surface) { // NOLINT(readability-convert-member-functions-to-static) - if (tiles.size() <= 1) { - return; - } - - int i = 0; - while (i < static_cast(tiles.size()) - 1) { - LineHorizontal line; - line.x1 = (tiles[i] % MAP_WIDTH) * TILE_SIZE; - - // Calcula Y segun si es superficie inferior o superior - if (is_bottom_surface) { - line.y = ((tiles[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - } else { - line.y = (tiles[i] / MAP_WIDTH) * TILE_SIZE; - } - - int last_one = i; - i++; - - // Encuentra tiles consecutivos - if (i < static_cast(tiles.size())) { - while (tiles[i] == tiles[i - 1] + 1) { - last_one = i; - i++; - if (i >= static_cast(tiles.size())) { - break; - } - } - } - - line.x2 = ((tiles[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - lines.push_back(line); - - // Salta separadores - if (i < static_cast(tiles.size()) && tiles[i] == -1) { - i++; - } - } -} - -// === Métodos de generación de geometría === - -// Calcula las superficies inferiores -void CollisionMap::setBottomSurfaces() { - std::vector tile = collectBottomTiles(); - buildHorizontalLines(tile, bottom_floors_, true); -} - -// Calcula las superficies superiores -void CollisionMap::setTopSurfaces() { - std::vector tile = collectTopTiles(); - buildHorizontalLines(tile, top_floors_, false); -} - -// Calcula las superficies laterales izquierdas -void CollisionMap::setLeftSurfaces() { // NOLINT(readability-make-member-function-const) - std::vector tile; - - // Busca todos los tiles de tipo muro que no tienen a su izquierda un tile de tipo muro - // Hay que recorrer la habitación por columnas (excepto los de la primera columna) - for (int i = 1; i < MAP_WIDTH; ++i) { - for (int j = 0; j < MAP_HEIGHT; ++j) { - const int POS = ((j * MAP_WIDTH) + i); - if (getTile(POS) == Tile::WALL && getTile(POS - 1) != Tile::WALL) { - tile.push_back(POS); - } - } - } - - // Añade un terminador - tile.push_back(-1); - - // Recorre el vector de tiles buscando tiles consecutivos - // (Los tiles de la misma columna, la diferencia entre ellos es de mapWidth) - // para localizar las superficies - if ((int)tile.size() > 1) { - int i = 0; - do { - LineVertical line; - line.x = (tile[i] % MAP_WIDTH) * TILE_SIZE; - line.y1 = ((tile[i] / MAP_WIDTH) * TILE_SIZE); - while (tile[i] + MAP_WIDTH == tile[i + 1]) { - if (i == (int)tile.size() - 1) { - break; - } - i++; - } - line.y2 = ((tile[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - left_walls_.push_back(line); - i++; - } while (i < (int)tile.size() - 1); - } -} - -// Calcula las superficies laterales derechas -void CollisionMap::setRightSurfaces() { // NOLINT(readability-make-member-function-const) - std::vector tile; - - // Busca todos los tiles de tipo muro que no tienen a su derecha un tile de tipo muro - // Hay que recorrer la habitación por columnas (excepto los de la última columna) - for (int i = 0; i < MAP_WIDTH - 1; ++i) { - for (int j = 0; j < MAP_HEIGHT; ++j) { - const int POS = ((j * MAP_WIDTH) + i); - if (getTile(POS) == Tile::WALL && getTile(POS + 1) != Tile::WALL) { - tile.push_back(POS); - } - } - } - - // Añade un terminador - tile.push_back(-1); - - // Recorre el vector de tiles buscando tiles consecutivos - // (Los tiles de la misma columna, la diferencia entre ellos es de mapWidth) - // para localizar las superficies - if ((int)tile.size() > 1) { - int i = 0; - do { - LineVertical line; - line.x = ((tile[i] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - line.y1 = ((tile[i] / MAP_WIDTH) * TILE_SIZE); - while (tile[i] + MAP_WIDTH == tile[i + 1]) { - if (i == (int)tile.size() - 1) { - break; - } - i++; - } - line.y2 = ((tile[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - right_walls_.push_back(line); - i++; - } while (i < (int)tile.size() - 1); - } -} - -// Encuentra todas las rampas que suben hacia la izquierda -void CollisionMap::setLeftSlopes() { // NOLINT(readability-make-member-function-const) - // Recorre la habitación entera por filas buscando tiles de tipo t_slope_l - std::vector found; - for (int i = 0; i < (int)collision_tile_map_.size(); ++i) { - if (getTile(i) == Tile::SLOPE_L) { - found.push_back(i); - } - } - - // El primer elemento es el inicio de una rampa. Se añade ese elemento y se buscan los siguientes, - // que seran i + mapWidth + 1. Conforme se añaden se eliminan y se vuelve a escudriñar el vector de - // tiles encontrados hasta que esté vacío - - while (!found.empty()) { - LineDiagonal line; - line.x1 = (found[0] % MAP_WIDTH) * TILE_SIZE; - line.y1 = (found[0] / MAP_WIDTH) * TILE_SIZE; - int looking_for = found[0] + MAP_WIDTH + 1; - int last_one_found = found[0]; - found.erase(found.begin()); - for (int i = 0; i < (int)found.size(); ++i) { - if (found[i] == looking_for) { - last_one_found = looking_for; - looking_for += MAP_WIDTH + 1; - found.erase(found.begin() + i); - i--; - } - } - line.x2 = ((last_one_found % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - line.y2 = ((last_one_found / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - left_slopes_.push_back(line); - } -} - -// Encuentra todas las rampas que suben hacia la derecha -void CollisionMap::setRightSlopes() { // NOLINT(readability-make-member-function-const) - // Recorre la habitación entera por filas buscando tiles de tipo t_slope_r - std::vector found; - for (int i = 0; i < (int)collision_tile_map_.size(); ++i) { - if (getTile(i) == Tile::SLOPE_R) { - found.push_back(i); - } - } - - // El primer elemento es el inicio de una rampa. Se añade ese elemento y se buscan los siguientes, - // que seran i + mapWidth - 1. Conforme se añaden se eliminan y se vuelve a escudriñar el vector de - // tiles encontrados hasta que esté vacío - - while (!found.empty()) { - LineDiagonal line; - line.x1 = ((found[0] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - line.y1 = (found[0] / MAP_WIDTH) * TILE_SIZE; - int looking_for = found[0] + MAP_WIDTH - 1; - int last_one_found = found[0]; - found.erase(found.begin()); - for (int i = 0; i < (int)found.size(); ++i) { - if (found[i] == looking_for) { - last_one_found = looking_for; - looking_for += MAP_WIDTH - 1; - found.erase(found.begin() + i); - i--; - } - } - line.x2 = (last_one_found % MAP_WIDTH) * TILE_SIZE; - line.y2 = ((last_one_found / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1; - right_slopes_.push_back(line); - } -} - -// Calcula las superficies automaticas (conveyor belts) -void CollisionMap::setAutoSurfaces() { - std::vector tile = collectConveyorTiles(); - buildHorizontalLines(tile, conveyor_belt_floors_, false); -} + tile_collider_(collision_tile_map_) {} diff --git a/source/game/gameplay/collision_map.hpp b/source/game/gameplay/collision_map.hpp index 8817ac8..40f4df5 100644 --- a/source/game/gameplay/collision_map.hpp +++ b/source/game/gameplay/collision_map.hpp @@ -1,123 +1,31 @@ #pragma once -#include +#include -#include // Para vector - -#include "game/gameplay/tile_collider.hpp" // Para TileCollider -#include "utils/defines.hpp" // Para Tile::SIZE, Map::WIDTH, Map::HEIGHT -#include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical +#include "game/gameplay/tile_collider.hpp" /** * @brief Mapa de colisiones de una habitación * - * Responsabilidades: - * - Almacenar la geometría de colisión (superficies, rampas, conveyor belts) - * - Generar geometría a partir del tilemap - * - Proporcionar queries de colisión para Player y otras entidades - * - Determinar tipo de tile en posiciones específicas + * Contiene el collision_tile_map (grid de tipos de tile) y el TileCollider + * que proporciona queries de colisión directas contra el grid. */ class CollisionMap { public: - // Enumeración de tipos de tile (para colisiones) - enum class Tile { - EMPTY, - WALL, - PASSABLE, - SLOPE_L, - SLOPE_R, - KILL, - ANIMATED - }; - - /** - * @brief Constructor - * @param collision_tile_map Mapa de colisiones por tile (0=vacío, 1=muro, 2=passable, 3=slope_l, 4=slope_r, 5=kill, 6=conveyor) - * @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1) - */ CollisionMap(std::vector collision_tile_map, int conveyor_belt_direction); ~CollisionMap() = default; - // Prohibir copia y movimiento CollisionMap(const CollisionMap&) = delete; auto operator=(const CollisionMap&) -> CollisionMap& = delete; CollisionMap(CollisionMap&&) = delete; auto operator=(CollisionMap&&) -> CollisionMap& = delete; - // --- Queries de tipo de tile --- - [[nodiscard]] auto getTile(SDL_FPoint point) const -> Tile; // Devuelve el tipo de tile en un punto (pixel) - [[nodiscard]] auto getTile(int index) const -> Tile; // Devuelve el tipo de tile en un índice del tilemap - - // --- Queries de colisión con superficies --- - auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes derechas (retorna X) - auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes izquierdas (retorna X) - auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Colisión con techos (retorna Y) - auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Colisión punto con techos - auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Colisión con suelos (retorna Y) - - // --- Queries de colisión con superficies automáticas (conveyor belts) --- - auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Colisión con conveyor belts (retorna Y) - auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Colisión punto con conveyor belts - - // --- Queries de colisión con rampas --- - auto checkLeftSlopes(const LineVertical& line) -> int; // Colisión línea con rampas izquierdas (retorna Y) - auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas - auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y) - auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas - [[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto - - // --- Métodos estáticos --- - static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels - static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Altura de rampa en un punto - - // --- Getters --- - [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } [[nodiscard]] auto getTileCollider() const -> const TileCollider& { return tile_collider_; } - - // Getters para debug visualization - [[nodiscard]] auto getBottomFloors() const -> const std::vector& { return bottom_floors_; } - [[nodiscard]] auto getTopFloors() const -> const std::vector& { return top_floors_; } - [[nodiscard]] auto getLeftWalls() const -> const std::vector& { return left_walls_; } - [[nodiscard]] auto getRightWalls() const -> const std::vector& { return right_walls_; } - [[nodiscard]] auto getLeftSlopes() const -> const std::vector& { return left_slopes_; } - [[nodiscard]] auto getRightSlopes() const -> const std::vector& { return right_slopes_; } - [[nodiscard]] auto getConveyorBeltFloors() const -> const std::vector& { return conveyor_belt_floors_; } + [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } + [[nodiscard]] auto getCollisionTileMap() const -> const std::vector& { return collision_tile_map_; } private: - // --- Constantes --- - static constexpr int TILE_SIZE = ::Tile::SIZE; // Tamaño del tile en pixels - static constexpr int MAP_WIDTH = ::Map::WIDTH; // Ancho del mapa en tiles - static constexpr int MAP_HEIGHT = ::Map::HEIGHT; // Alto del mapa en tiles - - // --- Datos de la habitación --- - std::vector collision_tile_map_; // Mapa de colisiones por tile - int conveyor_belt_direction_; // Dirección de conveyor belts - TileCollider tile_collider_; // Sistema de colisión por tiles - - // --- Geometría de colisión --- - std::vector bottom_floors_; // Superficies inferiores (suelos) - std::vector top_floors_; // Superficies superiores (techos) - std::vector left_walls_; // Paredes izquierdas - std::vector right_walls_; // Paredes derechas - std::vector left_slopes_; // Rampas que suben hacia la izquierda - std::vector right_slopes_; // Rampas que suben hacia la derecha - std::vector conveyor_belt_floors_; // Superficies automáticas (conveyor belts) - - // --- Métodos privados de generación de geometría --- - void initializeSurfaces(); // Inicializa todas las superficies de colisión - - // Helpers para recopilar tiles - auto collectBottomTiles() -> std::vector; // Tiles con superficie inferior - auto collectTopTiles() -> std::vector; // Tiles con superficie superior - auto collectConveyorTiles() -> std::vector; // Tiles conveyor belt - - // Construcción de geometría - static void buildHorizontalLines(const std::vector& tiles, std::vector& lines, bool is_bottom_surface); - void setBottomSurfaces(); // Calcula superficies inferiores - void setTopSurfaces(); // Calcula superficies superiores - void setLeftSurfaces(); // Calcula paredes izquierdas - void setRightSurfaces(); // Calcula paredes derechas - void setLeftSlopes(); // Calcula rampas izquierdas - void setRightSlopes(); // Calcula rampas derechas - void setAutoSurfaces(); // Calcula conveyor belts + std::vector collision_tile_map_; + int conveyor_belt_direction_; + TileCollider tile_collider_; }; diff --git a/source/game/gameplay/room.cpp b/source/game/gameplay/room.cpp index aa93f02..8ca949d 100644 --- a/source/game/gameplay/room.cpp +++ b/source/game/gameplay/room.cpp @@ -31,7 +31,7 @@ Room::Room(const std::string& room_path, std::shared_ptr data) // Crea el renderizador del tilemap (necesita tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_) tilemap_renderer_ = std::make_unique(tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_); - tilemap_renderer_->initialize(collision_map_.get()); // Inicializa (crea map_surface, pinta tiles, busca animados) + tilemap_renderer_->initialize(room->collision_tile_map); Screen::get()->setBorderColor(border_color_); // Establece el color del borde } @@ -96,7 +96,7 @@ void Room::renderItems() { #ifdef _DEBUG // Redibuja el mapa (para actualizar modo debug) void Room::redrawMap() { - tilemap_renderer_->redrawMap(collision_map_.get()); + tilemap_renderer_->redrawMap(collision_map_->getCollisionTileMap()); } // Actualiza animaciones sin mover enemigos (para editor de mapas) @@ -123,7 +123,7 @@ void Room::setTile(int index, int tile_value) { void Room::setBgColor(Uint8 color) { bg_color_ = color; tilemap_renderer_->setBgColor(color); - tilemap_renderer_->redrawMap(collision_map_.get()); + tilemap_renderer_->redrawMap(collision_map_->getCollisionTileMap()); } // Cambia colores de items en vivo (para editor) @@ -181,99 +181,14 @@ auto Room::getRoom(Border border) -> std::string { // NOLINT(readability-conver } } -// Devuelve el tipo de tile que hay en ese pixel -auto Room::getTile(SDL_FPoint point) -> Tile { // NOLINT(readability-convert-member-functions-to-static) - // Delega a CollisionMap y convierte el resultado - const auto COLLISION_TILE = collision_map_->getTile(point); - return static_cast(COLLISION_TILE); -} - -// Devuelve el tipo de tile en un índice del tilemap -auto Room::getTile(int index) -> Tile { // NOLINT(readability-convert-member-functions-to-static) - // Delega a CollisionMap y convierte el resultado - const auto COLLISION_TILE = collision_map_->getTile(index); - return static_cast(COLLISION_TILE); -} - -// Indica si hay colision con un enemigo a partir de un rectangulo auto Room::enemyCollision(SDL_FRect& rect) -> bool { return enemy_manager_->checkCollision(rect); } -// Indica si hay colision con un objeto a partir de un rectangulo auto Room::itemCollision(SDL_FRect& rect) -> bool { return item_manager_->checkCollision(rect); } -// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile -auto Room::getSlopeHeight(SDL_FPoint p, Tile slope) -> int { - // Delega a CollisionMap (método estático) - const auto COLLISION_TILE = static_cast(slope); - return CollisionMap::getSlopeHeight(p, COLLISION_TILE); -} - -// === Métodos de colisión (delegados a CollisionMap) === - -// Comprueba las colisiones con paredes derechas -auto Room::checkRightSurfaces(const SDL_FRect& rect) -> int { - return collision_map_->checkRightSurfaces(rect); -} - -// Comprueba las colisiones con paredes izquierdas -auto Room::checkLeftSurfaces(const SDL_FRect& rect) -> int { - return collision_map_->checkLeftSurfaces(rect); -} - -// Comprueba las colisiones con techos -auto Room::checkTopSurfaces(const SDL_FRect& rect) -> int { - return collision_map_->checkTopSurfaces(rect); -} - -// Comprueba las colisiones punto con techos -auto Room::checkTopSurfaces(const SDL_FPoint& p) -> bool { - return collision_map_->checkTopSurfaces(p); -} - -// Comprueba las colisiones con suelos -auto Room::checkBottomSurfaces(const SDL_FRect& rect) -> int { - return collision_map_->checkBottomSurfaces(rect); -} - -// Comprueba las colisiones con conveyor belts -auto Room::checkAutoSurfaces(const SDL_FRect& rect) -> int { - return collision_map_->checkAutoSurfaces(rect); -} - -// Comprueba las colisiones punto con conveyor belts -auto Room::checkConveyorBelts(const SDL_FPoint& p) -> bool { - return collision_map_->checkConveyorBelts(p); -} - -// Comprueba las colisiones línea con rampas izquierdas -auto Room::checkLeftSlopes(const LineVertical& line) -> int { - return collision_map_->checkLeftSlopes(line); -} - -// Comprueba las colisiones punto con rampas izquierdas -auto Room::checkLeftSlopes(const SDL_FPoint& p) -> bool { - return collision_map_->checkLeftSlopes(p); -} - -// Comprueba las colisiones línea con rampas derechas -auto Room::checkRightSlopes(const LineVertical& line) -> int { - return collision_map_->checkRightSlopes(line); -} - -// Comprueba las colisiones punto con rampas derechas -auto Room::checkRightSlopes(const SDL_FPoint& p) -> bool { - return collision_map_->checkRightSlopes(p); -} - -// Obtiene puntero a slope en un punto -auto Room::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { - return collision_map_->getSlopeAtPoint(p); -} - // Carga una habitación desde un archivo YAML (delegado a RoomLoader) auto Room::loadYAML(const std::string& file_path, bool verbose) -> Data { // NOLINT(readability-convert-member-functions-to-static) return RoomLoader::loadYAML(file_path, verbose); diff --git a/source/game/gameplay/room.hpp b/source/game/gameplay/room.hpp index 2193d3c..32c5b04 100644 --- a/source/game/gameplay/room.hpp +++ b/source/game/gameplay/room.hpp @@ -10,9 +10,7 @@ #include "game/entities/item.hpp" // Para ItemData #include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data #include "utils/defines.hpp" // Para Tile::SIZE, Map::WIDTH, Map::HEIGHT -#include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical -class Sprite; // lines 12-12 -class Surface; // lines 13-13 +class Surface; class EnemyManager; class ItemManager; class CollisionMap; @@ -30,114 +28,84 @@ class Room { NONE = 4 }; - enum class Tile { - EMPTY, - WALL, - PASSABLE, - SLOPE_L, - SLOPE_R, - KILL, - ANIMATED - }; - struct Data { - std::string number; // Numero de la habitación - Uint8 bg_color{0}; // Color de fondo de la habitación - Uint8 border_color{0}; // Color del borde de la pantalla - Uint8 item_color1{12}; // Color 1 para los items de la habitación - Uint8 item_color2{6}; // Color 2 para los items de la habitación - std::string upper_room; // Identificador de la habitación que se encuentra arriba - std::string lower_room; // Identificador de la habitación que se encuentra abajo - std::string left_room; // Identificador de la habitación que se encuentra a la izquierda - std::string right_room; // Identificador de la habitación que se encuentra a la derecha - std::string tile_set_file; // Imagen con los gráficos para la habitación - int conveyor_belt_direction{0}; // Sentido en el que arrastran las superficies automáticas de la habitación - std::vector tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML) - std::vector collision_tile_map; // Mapa de colisiones por tile (0=vacío, 1=sólido) - std::vector enemies; // Listado con los enemigos de la habitación - std::vector items; // Listado con los items que hay en la habitación + std::string number; + Uint8 bg_color{0}; + Uint8 border_color{0}; + Uint8 item_color1{12}; + Uint8 item_color2{6}; + std::string upper_room; + std::string lower_room; + std::string left_room; + std::string right_room; + std::string tile_set_file; + int conveyor_belt_direction{0}; + std::vector tile_map; + std::vector collision_tile_map; + std::vector enemies; + std::vector items; }; // Constructor y destructor Room(const std::string& room_path, std::shared_ptr data); - ~Room(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations + ~Room(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) // --- Funciones --- - [[nodiscard]] auto getNumber() const -> const std::string& { return number_; } // Devuelve el numero de la habitación - [[nodiscard]] auto getBGColor() const -> Uint8 { return bg_color_; } // Devuelve el color de la habitación - [[nodiscard]] auto getBorderColor() const -> Uint8 { return border_color_; } // Devuelve el color del borde - void renderMap(); // Dibuja el mapa en pantalla - void renderEnemies(); // Dibuja los enemigos en pantalla - void renderItems(); // Dibuja los objetos en pantalla + [[nodiscard]] auto getNumber() const -> const std::string& { return number_; } + [[nodiscard]] auto getBGColor() const -> Uint8 { return bg_color_; } + [[nodiscard]] auto getBorderColor() const -> Uint8 { return border_color_; } + void renderMap(); + void renderEnemies(); + void renderItems(); #ifdef _DEBUG - void redrawMap(); // Redibuja el mapa (para actualizar modo debug) - void updateEditorMode(float delta_time); // Actualiza animaciones sin mover enemigos (para editor) - void resetEnemyPositions(const std::vector& enemy_data); // Resetea enemigos a posiciones iniciales - auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); } // Acceso al gestor de enemigos (para editor) - auto getItemManager() -> ItemManager* { return item_manager_.get(); } // Acceso al gestor de items (para editor) - void setBgColor(Uint8 color); // Cambia color de fondo y redibuja (para editor) - void setItemColors(Uint8 color1, Uint8 color2); // Cambia colores de items (para editor) - void setTile(int index, int tile_value); // Cambia un tile y redibuja (para editor) + void redrawMap(); + void updateEditorMode(float delta_time); + void resetEnemyPositions(const std::vector& enemy_data); + auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); } + auto getItemManager() -> ItemManager* { return item_manager_.get(); } + void setBgColor(Uint8 color); + void setItemColors(Uint8 color1, Uint8 color2); + void setTile(int index, int tile_value); [[nodiscard]] auto getTileSetFile() const -> const std::string& { return tile_set_file_; } [[nodiscard]] auto getTileSetWidth() const -> int { return tile_set_width_; } #endif - void update(float delta_time); // Actualiza las variables y objetos de la habitación - auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde - auto getTile(SDL_FPoint point) -> Tile; // Devuelve el tipo de tile que hay en ese pixel - auto getTile(int index) -> Tile; // Devuelve el tipo de tile en un índice del tilemap - auto enemyCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un enemigo a partir de un rectangulo - auto itemCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un objeto a partir de un rectangulo - static auto getTileSize() -> int { return TILE_SIZE; } // Obten el tamaño del tile - static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile - auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones - auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones - auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones - auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones - auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones - auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Comprueba las colisiones - auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Comprueba las colisiones - auto checkLeftSlopes(const LineVertical& line) -> int; // Comprueba las colisiones - auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones - auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones - auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones - [[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto - void setPaused(bool value); // Pone el mapa en modo pausa - [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas + void update(float delta_time); + auto getRoom(Border border) -> std::string; + auto enemyCollision(SDL_FRect& rect) -> bool; + auto itemCollision(SDL_FRect& rect) -> bool; + void setPaused(bool value); + [[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } [[nodiscard]] auto getTileCollider() const -> const TileCollider&; // Método de carga de archivos YAML (delegado a RoomLoader) - static auto loadYAML(const std::string& file_path, bool verbose = false) -> Data; // Carga habitación desde archivo YAML unificado + static auto loadYAML(const std::string& file_path, bool verbose = false) -> Data; private: - // Constantes - static constexpr int TILE_SIZE = ::Tile::SIZE; // Ancho del tile en pixels - static constexpr int MAP_WIDTH = ::Map::WIDTH; // Ancho del mapa en tiles - static constexpr int MAP_HEIGHT = ::Map::HEIGHT; // Alto del mapa en tiles + static constexpr int TILE_SIZE = ::Tile::SIZE; + static constexpr int MAP_WIDTH = ::Map::WIDTH; + static constexpr int MAP_HEIGHT = ::Map::HEIGHT; - // Objetos y punteros - std::unique_ptr enemy_manager_; // Gestor de enemigos de la habitación - std::unique_ptr item_manager_; // Gestor de items de la habitación - std::unique_ptr collision_map_; // Mapa de colisiones de la habitación - std::unique_ptr tilemap_renderer_; // Renderizador del mapa de tiles - std::shared_ptr surface_; // Textura con los graficos de la habitación - std::shared_ptr data_; // Puntero a los datos del marcador + std::unique_ptr enemy_manager_; + std::unique_ptr item_manager_; + std::unique_ptr collision_map_; + std::unique_ptr tilemap_renderer_; + std::shared_ptr surface_; + std::shared_ptr data_; - // --- Variables --- - std::string number_; // Numero de la habitación - Uint8 bg_color_{0}; // Color de fondo de la habitación - Uint8 border_color_{0}; // Color del borde de la pantalla - Uint8 item_color1_{12}; // Color 1 para los items de la habitación - Uint8 item_color2_{6}; // Color 2 para los items de la habitación - std::string upper_room_; // Identificador de la habitación que se encuentra arriba - std::string lower_room_; // Identificador de la habitación que se encuentra abajp - std::string left_room_; // Identificador de la habitación que se encuentra a la izquierda - std::string right_room_; // Identificador de la habitación que se encuentra a la derecha - std::string tile_set_file_; // Imagen con los graficos para la habitación - std::vector tile_map_; // Indice de los tiles a dibujar en la habitación (embebido desde YAML) - int conveyor_belt_direction_{0}; // Sentido en el que arrastran las superficies automáticas de la habitación - bool is_paused_{false}; // Indica si el mapa esta en modo pausa - int tile_set_width_{0}; // Ancho del tileset en tiles + std::string number_; + Uint8 bg_color_{0}; + Uint8 border_color_{0}; + Uint8 item_color1_{12}; + Uint8 item_color2_{6}; + std::string upper_room_; + std::string lower_room_; + std::string left_room_; + std::string right_room_; + std::string tile_set_file_; + std::vector tile_map_; + int conveyor_belt_direction_{0}; + bool is_paused_{false}; + int tile_set_width_{0}; - // --- Funciones --- - void initializeRoom(const Data& room); // Inicializa los valores -}; \ No newline at end of file + void initializeRoom(const Data& room); +}; diff --git a/source/game/gameplay/tilemap_renderer.cpp b/source/game/gameplay/tilemap_renderer.cpp index 7a284fb..af77d46 100644 --- a/source/game/gameplay/tilemap_renderer.cpp +++ b/source/game/gameplay/tilemap_renderer.cpp @@ -4,48 +4,34 @@ #include "core/rendering/sprite/sprite.hpp" #include "core/rendering/surface.hpp" #ifdef _DEBUG +#include "core/resources/resource_cache.hpp" // Para Resource::Cache (collision.gif) #include "core/system/debug.hpp" #endif -#include "game/gameplay/collision_map.hpp" -#include "utils/utils.hpp" -// Constructor TilemapRenderer::TilemapRenderer(std::vector tile_map, int tile_set_width, std::shared_ptr tileset_surface, Uint8 bg_color, int conveyor_belt_direction) : tile_map_(std::move(tile_map)), tile_set_width_(tile_set_width), tileset_surface_(std::move(tileset_surface)), bg_color_(bg_color), conveyor_belt_direction_(conveyor_belt_direction) { - // Crear la surface del mapa map_surface_ = std::make_shared(PlayArea::WIDTH, PlayArea::HEIGHT); } -// Inicializa el renderizador -void TilemapRenderer::initialize(const CollisionMap* collision_map) { - setAnimatedTiles(collision_map); - fillMapTexture(collision_map); +void TilemapRenderer::initialize(const std::vector& collision_tile_map) { + setAnimatedTiles(collision_tile_map); + fillMapTexture(collision_tile_map); } -// Actualiza las animaciones de tiles void TilemapRenderer::update(float delta_time) { - if (is_paused_) { - return; - } - - // Actualiza el acumulador de tiempo + if (is_paused_) { return; } time_accumulator_ += delta_time; - - // Actualiza los tiles animados updateAnimatedTiles(); } -// Renderiza el mapa completo en pantalla void TilemapRenderer::render() { - // Dibuja la textura con el mapa en pantalla SDL_FRect dest = {.x = 0, .y = 0, .w = PlayArea::WIDTH, .h = PlayArea::HEIGHT}; map_surface_->render(nullptr, &dest); -// Dibuja los tiles animados #ifdef _DEBUG if (!Debug::get()->isEnabled()) { renderAnimatedTiles(); @@ -56,52 +42,11 @@ void TilemapRenderer::render() { } #ifdef _DEBUG -// Renderiza las superficies de colisión en modo debug (función helper estática) -static void renderDebugCollisionSurfaces(const CollisionMap* collision_map) { - auto surface = Screen::get()->getRendererSurface(); - - // BottomSurfaces - for (auto l : collision_map->getBottomFloors()) { - surface->drawLine(l.x1, l.y, l.x2, l.y, 2); - } - - // TopSurfaces - for (auto l : collision_map->getTopFloors()) { - surface->drawLine(l.x1, l.y, l.x2, l.y, 4); - } - - // LeftSurfaces - for (auto l : collision_map->getLeftWalls()) { - surface->drawLine(l.x, l.y1, l.x, l.y2, 8); - } - - // RightSurfaces - for (auto l : collision_map->getRightWalls()) { - surface->drawLine(l.x, l.y1, l.x, l.y2, 6); - } - - // LeftSlopes - for (auto l : collision_map->getLeftSlopes()) { - surface->drawLine(l.x1, l.y1, l.x2, l.y2, 10); - } - - // RightSlopes - for (auto l : collision_map->getRightSlopes()) { - surface->drawLine(l.x1, l.y1, l.x2, l.y2, 12); - } - - // AutoSurfaces (Conveyor Belts) - for (auto l : collision_map->getConveyorBeltFloors()) { - surface->drawLine(l.x1, l.y, l.x2, l.y, 14); - } +// Redibuja el tilemap (para actualizar modo debug: pinta collision tilemap o tiles normales) +void TilemapRenderer::redrawMap(const std::vector& collision_tile_map) { + fillMapTexture(collision_tile_map); } -// Redibuja el tilemap (para actualizar modo debug) -void TilemapRenderer::redrawMap(const CollisionMap* collision_map) { - fillMapTexture(collision_map); -} - -// Cambia un tile y repinta solo esa celda en la map_surface void TilemapRenderer::setTile(int index, int tile_value) { if (index < 0 || index >= static_cast(tile_map_.size())) { return; } @@ -113,11 +58,9 @@ void TilemapRenderer::setTile(int index, int tile_value) { auto previous_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(map_surface_); - // Borrar la celda con el color de fondo SDL_FRect cell = {.x = static_cast(col * TILE_SIZE), .y = static_cast(row * TILE_SIZE), .w = static_cast(TILE_SIZE), .h = static_cast(TILE_SIZE)}; map_surface_->fillRect(&cell, bg_color_); - // Dibujar el nuevo tile (si no es vacío ni animado) if (tile_value > -1) { const bool IS_ANIMATED = (tile_value >= 18 * tile_set_width_) && (tile_value < 19 * tile_set_width_); if (!IS_ANIMATED) { @@ -131,27 +74,44 @@ void TilemapRenderer::setTile(int index, int tile_value) { Screen::get()->setRendererSurface(previous_renderer); } + +// Renderiza el collision tilemap superpuesto (modo debug) +static void renderDebugCollisionTilemap(const std::vector& collision_tile_map) { + auto collision_surface = Resource::Cache::get()->getSurface("collision.gif"); + if (!collision_surface) { return; } + + for (int y = 0; y < Map::HEIGHT; ++y) { + for (int x = 0; x < Map::WIDTH; ++x) { + int index = (y * Map::WIDTH) + x; + if (index >= static_cast(collision_tile_map.size())) { continue; } + int tile = collision_tile_map[index]; + if (tile <= 0) { continue; } + SDL_FRect clip = { + .x = static_cast(tile * Tile::SIZE), + .y = 0, + .w = static_cast(Tile::SIZE), + .h = static_cast(Tile::SIZE)}; + collision_surface->render(x * Tile::SIZE, y * Tile::SIZE, &clip); + } + } +} #endif -// Pinta el mapa estático y debug lines -void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) { // NOLINT(readability-convert-member-functions-to-static) +// Pinta el mapa estático +void TilemapRenderer::fillMapTexture(const std::vector& collision_tile_map) { auto previous_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(map_surface_); map_surface_->clear(bg_color_); - // Los tileSetFiles son de 20x20 tiles. El primer tile es el 0. Cuentan hacia la derecha y hacia abajo - SDL_FRect clip = {.x = 0, .y = 0, .w = TILE_SIZE, .h = TILE_SIZE}; for (int y = 0; y < MAP_HEIGHT; ++y) { for (int x = 0; x < MAP_WIDTH; ++x) { - // Tiled pone los tiles vacios del mapa como cero y empieza a contar de 1 a n. - // Al cargar el mapa en memoria, se resta uno, por tanto los tiles vacios son -1 - // Tampoco hay que dibujar los tiles animados que estan en la fila 19 (indices) const int INDEX = (y * MAP_WIDTH) + x; - const bool A = (tile_map_[INDEX] >= 18 * tile_set_width_) && (tile_map_[INDEX] < 19 * tile_set_width_); - const bool B = tile_map_[INDEX] > -1; + // Los tiles animados (fila 18 del tileset) no se pintan en la textura estática + const bool IS_ANIMATED = (tile_map_[INDEX] >= 18 * tile_set_width_) && (tile_map_[INDEX] < 19 * tile_set_width_); + const bool HAS_TILE = tile_map_[INDEX] > -1; - if (B && !A) { + if (HAS_TILE && !IS_ANIMATED) { clip.x = (tile_map_[INDEX] % tile_set_width_) * TILE_SIZE; clip.y = (tile_map_[INDEX] / tile_set_width_) * TILE_SIZE; #ifdef _DEBUG @@ -166,25 +126,21 @@ void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) { // NO } #ifdef _DEBUG - // Pinta las superficies en el modo debug + // En modo debug, pintar el collision tilemap en vez de las líneas de colisión antiguas if (Debug::get()->isEnabled()) { - renderDebugCollisionSurfaces(collision_map); + renderDebugCollisionTilemap(collision_tile_map); } -#endif // _DEBUG +#endif Screen::get()->setRendererSurface(previous_renderer); } -// Localiza todos los tiles animados -void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) { // NOLINT(readability-convert-member-functions-to-static) - // Recorre la habitación entera por filas buscando tiles de tipo t_animated - for (int i = 0; i < (int)tile_map_.size(); ++i) { - const auto TILE_TYPE = collision_map->getTile(i); - if (TILE_TYPE == CollisionMap::Tile::ANIMATED) { - // La i es la ubicación +// Localiza tiles animados (conveyor belts) usando el collision_tile_map +void TilemapRenderer::setAnimatedTiles(const std::vector& collision_tile_map) { + for (int i = 0; i < static_cast(tile_map_.size()); ++i) { + // Un tile es animado si su valor en el collision tilemap es COLLISION_ANIMATED (6) + if (i < static_cast(collision_tile_map.size()) && collision_tile_map[i] == COLLISION_ANIMATED) { const int X = (i % MAP_WIDTH) * TILE_SIZE; const int Y = (i / MAP_WIDTH) * TILE_SIZE; - - // TileMap[i] es el tile a poner const int XC = (tile_map_[i] % tile_set_width_) * TILE_SIZE; const int YC = (tile_map_[i] / tile_set_width_) * TILE_SIZE; @@ -197,14 +153,10 @@ void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) { // } } -// Actualiza tiles animados -void TilemapRenderer::updateAnimatedTiles() { // NOLINT(readability-make-member-function-const) +void TilemapRenderer::updateAnimatedTiles() { const int NUM_FRAMES = 4; - - // Calcular frame actual basado en tiempo const int CURRENT_FRAME = static_cast(time_accumulator_ / CONVEYOR_FRAME_DURATION) % NUM_FRAMES; - // Calcular offset basado en dirección int offset = 0; if (conveyor_belt_direction_ == -1) { offset = CURRENT_FRAME * TILE_SIZE; @@ -219,7 +171,6 @@ void TilemapRenderer::updateAnimatedTiles() { // NOLINT(readability-make-member } } -// Renderiza tiles animados void TilemapRenderer::renderAnimatedTiles() { for (const auto& a : animated_tiles_) { a.sprite->render(); diff --git a/source/game/gameplay/tilemap_renderer.hpp b/source/game/gameplay/tilemap_renderer.hpp index 764231c..fb8ade8 100644 --- a/source/game/gameplay/tilemap_renderer.hpp +++ b/source/game/gameplay/tilemap_renderer.hpp @@ -3,118 +3,63 @@ #include #include // Para shared_ptr -#include // Para string #include // Para vector #include "utils/defines.hpp" class Surface; class Sprite; -class CollisionMap; -/** - * @brief Renderizador de tilemap de una habitación - * - * Responsabilidades: - * - Renderizar el mapa de tiles estático - * - Gestionar tiles animados (conveyor belts) - * - Actualizar animaciones basadas en tiempo - * - Renderizar debug visualization (en modo DEBUG) - */ class TilemapRenderer { public: - /** - * @brief Constructor - * @param tile_map Vector con índices de tiles de la habitación - * @param tile_set_width Ancho del tileset en tiles - * @param tileset_surface Surface con los gráficos del tileset - * @param bg_color Color de fondo de la habitación (como string) - * @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1) - */ TilemapRenderer(std::vector tile_map, int tile_set_width, std::shared_ptr tileset_surface, Uint8 bg_color, int conveyor_belt_direction); ~TilemapRenderer() = default; - // Prohibir copia y movimiento TilemapRenderer(const TilemapRenderer&) = delete; auto operator=(const TilemapRenderer&) -> TilemapRenderer& = delete; TilemapRenderer(TilemapRenderer&&) = delete; auto operator=(TilemapRenderer&&) -> TilemapRenderer& = delete; - /** - * @brief Inicializa el renderizador - * @param collision_map Mapa de colisiones para determinar tiles animados - * - * Crea la textura del mapa, pinta los tiles estáticos, y localiza tiles animados - */ - void initialize(const CollisionMap* collision_map); - - /** - * @brief Actualiza las animaciones de tiles - * @param delta_time Tiempo transcurrido desde el último frame (segundos) - */ + void initialize(const std::vector& collision_tile_map); void update(float delta_time); - - /** - * @brief Renderiza el mapa completo en pantalla - * - * Dibuja la textura del mapa y los tiles animados - */ void render(); #ifdef _DEBUG - /** - * @brief Redibuja el tilemap (para actualizar modo debug) - * @param collision_map Mapa de colisiones para dibujar líneas de debug - * - * Llamado cuando se activa/desactiva el modo debug para actualizar la visualización - */ - void redrawMap(const CollisionMap* collision_map); + void redrawMap(const std::vector& collision_tile_map); void setBgColor(Uint8 color) { bg_color_ = color; } - void setTile(int index, int tile_value); // Cambia un tile y repinta esa celda + void setTile(int index, int tile_value); #endif - /** - * @brief Activa/desactiva modo pausa - * @param paused true para pausar, false para reanudar - * - * Nota: Actualmente no afecta al renderizado, pero mantiene consistencia con Room - */ void setPaused(bool paused) { is_paused_ = paused; } - - // Getter para la surface del mapa (usado por Room para acceso directo si es necesario) [[nodiscard]] auto getMapSurface() const -> std::shared_ptr { return map_surface_; } private: - // Estructura para tiles animados (conveyor belts) struct AnimatedTile { - std::shared_ptr sprite{nullptr}; // SurfaceSprite para dibujar el tile - int x_orig{0}; // Posición X del primer tile de la animación en tilesheet + std::shared_ptr sprite{nullptr}; + int x_orig{0}; }; - // === Constantes === - static constexpr int TILE_SIZE = Tile::SIZE; // Ancho del tile en pixels - static constexpr int MAP_WIDTH = Map::WIDTH; // Ancho del mapa en tiles - static constexpr int MAP_HEIGHT = Map::HEIGHT; // Alto del mapa en tiles - static constexpr int PLAY_AREA_WIDTH = PlayArea::WIDTH; // Ancho del área de juego en pixels - static constexpr int PLAY_AREA_HEIGHT = PlayArea::HEIGHT; // Alto del área de juego en pixels - static constexpr float CONVEYOR_FRAME_DURATION = 0.05F; // Duración de cada frame (3 frames @ 60fps) + static constexpr int TILE_SIZE = Tile::SIZE; + static constexpr int MAP_WIDTH = Map::WIDTH; + static constexpr int MAP_HEIGHT = Map::HEIGHT; + static constexpr int PLAY_AREA_WIDTH = PlayArea::WIDTH; + static constexpr int PLAY_AREA_HEIGHT = PlayArea::HEIGHT; + static constexpr float CONVEYOR_FRAME_DURATION = 0.05F; + static constexpr int COLLISION_ANIMATED = 6; // Valor del tile de conveyor en el collision tilemap - // === Datos de la habitación === - std::vector tile_map_; // Índices de tiles de la habitación - int tile_set_width_; // Ancho del tileset en tiles - std::shared_ptr tileset_surface_; // Gráficos del tileset - Uint8 bg_color_{0}; // Color de fondo - int conveyor_belt_direction_; // Dirección de conveyor belts + std::vector tile_map_; + int tile_set_width_; + std::shared_ptr tileset_surface_; + Uint8 bg_color_{0}; + int conveyor_belt_direction_; - // === Renderizado === - std::shared_ptr map_surface_; // Textura para el mapa de la habitación - std::vector animated_tiles_; // Tiles animados (conveyor belts) - float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones - bool is_paused_{false}; // Indica si está en modo pausa + std::shared_ptr map_surface_; + std::vector animated_tiles_; + float time_accumulator_{0.0F}; + bool is_paused_{false}; - // === Métodos privados === - void fillMapTexture(const CollisionMap* collision_map); // Pinta el mapa estático y debug lines - void setAnimatedTiles(const CollisionMap* collision_map); // Localiza todos los tiles animados - void updateAnimatedTiles(); // Actualiza tiles animados - void renderAnimatedTiles(); // Renderiza tiles animados + void fillMapTexture(const std::vector& collision_tile_map); + void setAnimatedTiles(const std::vector& collision_tile_map); + void updateAnimatedTiles(); + void renderAnimatedTiles(); }; diff --git a/source/utils/utils.cpp b/source/utils/utils.cpp index 26578c5..f125678 100644 --- a/source/utils/utils.cpp +++ b/source/utils/utils.cpp @@ -132,156 +132,6 @@ auto checkCollision(const SDL_FPoint& point, const SDL_FRect& rect) -> bool { return true; } -// Detector de colisiones entre una linea horizontal y un rectangulo -auto checkCollision(const LineHorizontal& l, const SDL_FRect& rect) -> bool { - SDL_Rect r = toSDLRect(rect); - // Comprueba si la linea esta por encima del rectangulo - if (l.y < r.y) { - return false; - } - - // Comprueba si la linea esta por debajo del rectangulo - if (l.y >= r.y + r.h) { - return false; - } - - // Comprueba si el inicio de la linea esta a la derecha del rectangulo - if (l.x1 >= r.x + r.w) { - return false; - } - - // Comprueba si el final de la linea esta a la izquierda del rectangulo - if (l.x2 < r.x) { - return false; - } - - // Si ha llegado hasta aquí, hay colisión - return true; -} - -// Detector de colisiones entre una linea vertical y un rectangulo -auto checkCollision(const LineVertical& l, const SDL_FRect& rect) -> bool { - SDL_Rect r = toSDLRect(rect); - // Comprueba si la linea esta por la izquierda del rectangulo - if (l.x < r.x) { - return false; - } - - // Comprueba si la linea esta por la derecha del rectangulo - if (l.x >= r.x + r.w) { - return false; - } - - // Comprueba si el inicio de la linea esta debajo del rectangulo - if (l.y1 >= r.y + r.h) { - return false; - } - - // Comprueba si el final de la linea esta encima del rectangulo - if (l.y2 < r.y) { - return false; - } - - // Si ha llegado hasta aquí, hay colisión - return true; -} - -// Detector de colisiones entre una linea horizontal y un punto -auto checkCollision(const LineHorizontal& l, const SDL_FPoint& point) -> bool { - SDL_Point p = toSDLPoint(point); - - // Comprueba si el punto esta sobre la linea - if (p.y > l.y) { - return false; - } - - // Comprueba si el punto esta bajo la linea - if (p.y < l.y) { - return false; - } - - // Comprueba si el punto esta a la izquierda de la linea - if (p.x < l.x1) { - return false; - } - - // Comprueba si el punto esta a la derecha de la linea - if (p.x > l.x2) { - return false; - } - - // Si ha llegado aquí, hay colisión - return true; -} - -// Detector de colisiones entre dos lineas -auto checkCollision(const Line& l1, const Line& l2) -> SDL_Point { - const float X1 = l1.x1; - const float Y1 = l1.y1; - const float X2 = l1.x2; - const float Y2 = l1.y2; - - const float X3 = l2.x1; - const float Y3 = l2.y1; - const float X4 = l2.x2; - const float Y4 = l2.y2; - - // calculate the direction of the lines - float u_a = (((X4 - X3) * (Y1 - Y3)) - ((Y4 - Y3) * (X1 - X3))) / (((Y4 - Y3) * (X2 - X1)) - ((X4 - X3) * (Y2 - Y1))); - float u_b = (((X2 - X1) * (Y1 - Y3)) - ((Y2 - Y1) * (X1 - X3))) / (((Y4 - Y3) * (X2 - X1)) - ((X4 - X3) * (Y2 - Y1))); - - // if uA and uB are between 0-1, lines are colliding - if (u_a >= 0 && u_a <= 1 && u_b >= 0 && u_b <= 1) { - // Calcula la intersección - const float X = X1 + (u_a * (X2 - X1)); - const float Y = Y1 + (u_a * (Y2 - Y1)); - - return {.x = static_cast(std::round(X)), .y = static_cast(std::round(Y))}; - } - return {.x = -1, .y = -1}; -} - -// Detector de colisiones entre dos lineas -auto checkCollision(const LineDiagonal& l1, const LineVertical& l2) -> SDL_Point { - const float X1 = l1.x1; - const float Y1 = l1.y1; - const float X2 = l1.x2; - const float Y2 = l1.y2; - - const float X3 = l2.x; - const float Y3 = l2.y1; - const float X4 = l2.x; - const float Y4 = l2.y2; - - // calculate the direction of the lines - float u_a = (((X4 - X3) * (Y1 - Y3)) - ((Y4 - Y3) * (X1 - X3))) / (((Y4 - Y3) * (X2 - X1)) - ((X4 - X3) * (Y2 - Y1))); - float u_b = (((X2 - X1) * (Y1 - Y3)) - ((Y2 - Y1) * (X1 - X3))) / (((Y4 - Y3) * (X2 - X1)) - ((X4 - X3) * (Y2 - Y1))); - - // if uA and uB are between 0-1, lines are colliding - if (u_a >= 0 && u_a <= 1 && u_b >= 0 && u_b <= 1) { - // Calcula la intersección - const float X = X1 + (u_a * (X2 - X1)); - const float Y = Y1 + (u_a * (Y2 - Y1)); - - return {.x = static_cast(std::round(X)), .y = static_cast(std::round(Y))}; - } - return {.x = -1, .y = -1}; -} - -// Normaliza una linea diagonal -void normalizeLine(LineDiagonal& l) { - // Las lineas diagonales van de izquierda a derecha - // x2 mayor que x1 - if (l.x2 < l.x1) { - const int X = l.x1; - const int Y = l.y1; - l.x1 = l.x2; - l.y1 = l.y2; - l.x2 = X; - l.y2 = Y; - } -} - // Convierte SDL_FRect a SDL_Rect auto toSDLRect(const SDL_FRect& frect) -> SDL_Rect { SDL_Rect rect = { @@ -300,39 +150,6 @@ auto toSDLPoint(const SDL_FPoint& fpoint) -> SDL_Point { return point; } -// Detector de colisiones entre un punto y una linea diagonal -auto checkCollision(const SDL_FPoint& point, const LineDiagonal& l) -> bool { - SDL_Point p = toSDLPoint(point); - - // Comprueba si el punto está en alineado con la linea - if (abs(p.x - l.x1) != abs(p.y - l.y1)) { - return false; - } - - // Comprueba si está a la derecha de la linea - if (p.x > l.x1 && p.x > l.x2) { - return false; - } - - // Comprueba si está a la izquierda de la linea - if (p.x < l.x1 && p.x < l.x2) { - return false; - } - - // Comprueba si está por encima de la linea - if (p.y > l.y1 && p.y > l.y2) { - return false; - } - - // Comprueba si está por debajo de la linea - if (p.y < l.y1 && p.y < l.y2) { - return false; - } - - // En caso contrario, el punto está en la linea - return true; -} - // Convierte una cadena a un entero de forma segura auto safeStoi(const std::string& value, int default_value) -> int { try { diff --git a/source/utils/utils.hpp b/source/utils/utils.hpp index d17a556..947e79d 100644 --- a/source/utils/utils.hpp +++ b/source/utils/utils.hpp @@ -12,26 +12,6 @@ struct Circle { int r{0}; }; -// Estructura para definir una linea horizontal -struct LineHorizontal { - int x1{0}, x2{0}, y{0}; -}; - -// Estructura para definir una linea vertical -struct LineVertical { - int x{0}, y1{0}, y2{0}; -}; - -// Estructura para definir una linea diagonal -struct LineDiagonal { - int x1{0}, y1{0}, x2{0}, y2{0}; -}; - -// Estructura para definir una linea -struct Line { - int x1{0}, y1{0}, x2{0}, y2{0}; -}; - // Estructura para definir un color RGB struct Rgb { Uint8 r{0}; @@ -51,14 +31,6 @@ auto checkCollision(const Circle& a, const Circle& b) -> bool; auto checkCollision(const Circle& a, const SDL_FRect& rect) -> bool; // Colisión círculo-rectángulo auto checkCollision(const SDL_FRect& a, const SDL_FRect& b) -> bool; // Colisión rectángulo-rectángulo auto checkCollision(const SDL_FPoint& p, const SDL_FRect& r) -> bool; // Colisión punto-rectángulo -auto checkCollision(const LineHorizontal& l, const SDL_FRect& r) -> bool; // Colisión línea horizontal-rectángulo -auto checkCollision(const LineVertical& l, const SDL_FRect& r) -> bool; // Colisión línea vertical-rectángulo -auto checkCollision(const LineHorizontal& l, const SDL_FPoint& p) -> bool; // Colisión línea horizontal-punto -auto checkCollision(const Line& l1, const Line& l2) -> SDL_Point; // Colisión línea-línea (intersección) -auto checkCollision(const LineDiagonal& l1, const LineVertical& l2) -> SDL_Point; // Colisión diagonal-vertical -auto checkCollision(const SDL_FPoint& p, const LineDiagonal& l) -> bool; // Colisión punto-diagonal -void normalizeLine(LineDiagonal& l); // Normaliza línea diagonal (x1 < x2) - // CONVERSIONES DE TIPOS SDL auto toSDLRect(const SDL_FRect& frect) -> SDL_Rect; // Convierte SDL_FRect a SDL_Rect auto toSDLPoint(const SDL_FPoint& fpoint) -> SDL_Point; // Convierte SDL_FPoint a SDL_Point