collision map

This commit is contained in:
2026-04-06 20:27:35 +02:00
parent ef04500a44
commit 98715ef3a7
36 changed files with 489 additions and 297 deletions

View File

@@ -8,9 +8,8 @@
#include "utils/defines.hpp" // Para Collision
// Constructor
CollisionMap::CollisionMap(std::vector<int> tile_map, int tile_set_width, int conveyor_belt_direction)
: tile_map_(std::move(tile_map)),
tile_set_width_(tile_set_width),
CollisionMap::CollisionMap(std::vector<int> collision_tile_map, int conveyor_belt_direction)
: collision_tile_map_(std::move(collision_tile_map)),
conveyor_belt_direction_(conveyor_belt_direction) {
// Inicializa todas las superficies de colisión
initializeSurfaces();
@@ -35,43 +34,21 @@ auto CollisionMap::getTile(SDL_FPoint point) const -> Tile {
return getTile(POS);
}
// Devuelve el tipo de tile que hay en ese indice
auto CollisionMap::getTile(int index) const -> Tile { // NOLINT(readability-convert-member-functions-to-static)
const bool ON_RANGE = (index > -1) && (index < (int)tile_map_.size());
if (ON_RANGE) {
// Las filas 0-8 son de tiles t_wall
if ((tile_map_[index] >= 0) && (tile_map_[index] < 9 * tile_set_width_)) {
return Tile::WALL;
}
// Las filas 9-17 son de tiles t_passable
if ((tile_map_[index] >= 9 * tile_set_width_) && (tile_map_[index] < 18 * tile_set_width_)) {
return Tile::PASSABLE;
}
// Las filas 18-20 es de tiles t_animated
if ((tile_map_[index] >= 18 * tile_set_width_) && (tile_map_[index] < 21 * tile_set_width_)) {
return Tile::ANIMATED;
}
// La fila 21 es de tiles t_slope_r
if ((tile_map_[index] >= 21 * tile_set_width_) && (tile_map_[index] < 22 * tile_set_width_)) {
return Tile::SLOPE_R;
}
// La fila 22 es de tiles t_slope_l
if ((tile_map_[index] >= 22 * tile_set_width_) && (tile_map_[index] < 23 * tile_set_width_)) {
return Tile::SLOPE_L;
}
// La fila 23 es de tiles t_kill
if ((tile_map_[index] >= 23 * tile_set_width_) && (tile_map_[index] < 24 * tile_set_width_)) {
return Tile::KILL;
}
// 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<int>(collision_tile_map_.size())) {
return Tile::EMPTY;
}
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
@@ -234,7 +211,7 @@ auto CollisionMap::collectBottomTiles() -> std::vector<int> { // NOLINT(readabi
// 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)tile_map_.size() - MAP_WIDTH; ++i) {
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);
@@ -256,7 +233,7 @@ auto CollisionMap::collectTopTiles() -> std::vector<int> { // NOLINT(readabilit
// 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)tile_map_.size(); ++i) {
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);
@@ -272,13 +249,12 @@ auto CollisionMap::collectTopTiles() -> std::vector<int> { // NOLINT(readabilit
return tile;
}
// Helper: recopila tiles animados (para superficies automaticas/conveyor belts)
auto CollisionMap::collectAnimatedTiles() -> std::vector<int> { // NOLINT(readability-make-member-function-const)
// Helper: recopila tiles conveyor belt
auto CollisionMap::collectConveyorTiles() -> std::vector<int> { // NOLINT(readability-make-member-function-const)
std::vector<int> tile;
// Busca todos los tiles de tipo animado
// Hay que recorrer la habitación por filas (excepto los de la primera fila)
for (int i = MAP_WIDTH; i < (int)tile_map_.size(); ++i) {
// 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);
@@ -437,7 +413,7 @@ void CollisionMap::setRightSurfaces() { // NOLINT(readability-make-member-funct
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<int> found;
for (int i = 0; i < (int)tile_map_.size(); ++i) {
for (int i = 0; i < (int)collision_tile_map_.size(); ++i) {
if (getTile(i) == Tile::SLOPE_L) {
found.push_back(i);
}
@@ -472,7 +448,7 @@ void CollisionMap::setLeftSlopes() { // NOLINT(readability-make-member-function
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<int> found;
for (int i = 0; i < (int)tile_map_.size(); ++i) {
for (int i = 0; i < (int)collision_tile_map_.size(); ++i) {
if (getTile(i) == Tile::SLOPE_R) {
found.push_back(i);
}
@@ -505,6 +481,6 @@ void CollisionMap::setRightSlopes() { // NOLINT(readability-make-member-functio
// Calcula las superficies automaticas (conveyor belts)
void CollisionMap::setAutoSurfaces() {
std::vector<int> tile = collectAnimatedTiles();
std::vector<int> tile = collectConveyorTiles();
buildHorizontalLines(tile, conveyor_belt_floors_, false);
}

View File

@@ -5,7 +5,7 @@
#include <vector> // Para vector
#include "utils/defines.hpp" // Para Tile::SIZE, Map::WIDTH, Map::HEIGHT
#include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical
#include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical
/**
* @brief Mapa de colisiones de una habitación
@@ -31,11 +31,10 @@ class CollisionMap {
/**
* @brief Constructor
* @param tile_map Vector con índices de tiles de la habitación
* @param tile_set_width Ancho del tileset en tiles (para calcular tipo de tile)
* @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<int> tile_map, int tile_set_width, int conveyor_belt_direction);
CollisionMap(std::vector<int> collision_tile_map, int conveyor_belt_direction);
~CollisionMap() = default;
// Prohibir copia y movimiento
@@ -84,14 +83,13 @@ class CollisionMap {
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 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<int> tile_map_; // Índices de tiles de la habitación
int tile_set_width_; // Ancho del tileset en tiles
int conveyor_belt_direction_; // Dirección de conveyor belts
std::vector<int> collision_tile_map_; // Mapa de colisiones por tile
int conveyor_belt_direction_; // Dirección de conveyor belts
// --- Geometría de colisión ---
std::vector<LineHorizontal> bottom_floors_; // Superficies inferiores (suelos)
@@ -108,7 +106,7 @@ class CollisionMap {
// Helpers para recopilar tiles
auto collectBottomTiles() -> std::vector<int>; // Tiles con superficie inferior
auto collectTopTiles() -> std::vector<int>; // Tiles con superficie superior
auto collectAnimatedTiles() -> std::vector<int>; // Tiles animados (conveyor belts)
auto collectConveyorTiles() -> std::vector<int>; // Tiles conveyor belt
// Construcción de geometría
static void buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface);

View File

@@ -26,8 +26,8 @@ Room::Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data)
item_manager_ = std::make_unique<ItemManager>(room->number, data_);
initializeRoom(*room);
// Crea el mapa de colisiones (necesita tile_map_, tile_set_width_, conveyor_belt_direction_)
collision_map_ = std::make_unique<CollisionMap>(tile_map_, tile_set_width_, conveyor_belt_direction_);
// Crea el mapa de colisiones desde el collision_tile_map
collision_map_ = std::make_unique<CollisionMap>(room->collision_tile_map, conveyor_belt_direction_);
// Crea el renderizador del tilemap (necesita tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_)
tilemap_renderer_ = std::make_unique<TilemapRenderer>(tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_);
@@ -78,7 +78,6 @@ void Room::initializeRoom(const Data& room) {
}
}
// Dibuja el mapa en pantalla
void Room::renderMap() {
tilemap_renderer_->render();

View File

@@ -9,7 +9,7 @@
#include "game/entities/enemy.hpp" // Para EnemyData
#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/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
@@ -40,20 +40,21 @@ class Room {
};
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<int> tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML)
std::vector<Enemy::Data> enemies; // Listado con los enemigos de la habitación
std::vector<Item::Data> items; // Listado con los items que hay en la habitación
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<int> tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML)
std::vector<int> collision_tile_map; // Mapa de colisiones por tile (0=vacío, 1=sólido)
std::vector<Enemy::Data> enemies; // Listado con los enemigos de la habitación
std::vector<Item::Data> items; // Listado con los items que hay en la habitación
};
// Constructor y destructor
@@ -61,21 +62,21 @@ class Room {
~Room(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations
// --- 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_; } // 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
#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>& 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(); // 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>& 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)
[[nodiscard]] auto getTileSetFile() const -> const std::string& { return tile_set_file_; }
[[nodiscard]] auto getTileSetWidth() const -> int { return tile_set_width_; }
#endif
@@ -107,8 +108,8 @@ class Room {
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 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
// Objetos y punteros

View File

@@ -119,20 +119,12 @@ void RoomLoader::parseRoomConnections(const fkyaml::node& conn_node, Room::Data&
: "0";
}
// Parsea el tilemap de la habitación
void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("tilemap")) {
std::cerr << "Warning: No tilemap found in " << file_name << '\n';
return;
}
const auto& tilemap_node = yaml["tilemap"];
// Read 2D array
// Lee un array 2D de enteros desde un nodo YAML
static auto readTilemap2D(const fkyaml::node& node) -> std::vector<std::vector<int>> {
std::vector<std::vector<int>> tilemap_2d;
tilemap_2d.reserve(Map::HEIGHT);
for (const auto& row_node : tilemap_node) {
for (const auto& row_node : node) {
std::vector<int> row;
row.reserve(Map::WIDTH);
@@ -143,11 +135,36 @@ void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const
tilemap_2d.push_back(row);
}
// Convert to 1D flat array
room.tile_map = flattenTilemap(tilemap_2d);
return tilemap_2d;
}
// Parsea el tilemap de la habitación
void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("tilemap")) {
std::cerr << "Warning: No tilemap found in " << file_name << '\n';
return;
}
const auto& tilemap_node = yaml["tilemap"];
// Nuevo formato: tilemap.draw + tilemap.collision
if (tilemap_node.contains("draw")) {
room.tile_map = flattenTilemap(readTilemap2D(tilemap_node["draw"]));
if (tilemap_node.contains("collision")) {
room.collision_tile_map = flattenTilemap(readTilemap2D(tilemap_node["collision"]));
}
} else {
// Formato antiguo: tilemap es directamente el array 2D de dibujo
room.tile_map = flattenTilemap(readTilemap2D(tilemap_node));
}
if (verbose) {
std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles\n";
std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles";
if (!room.collision_tile_map.empty()) {
std::cout << " + collision: " << room.collision_tile_map.size() << " tiles";
}
std::cout << '\n';
}
}

View File

@@ -95,9 +95,7 @@ void Scoreboard::fillTexture() {
// Valores formateados
const std::string LIVES_STR = std::to_string(data_->lives);
const std::string ITEMS_STR = std::to_string(data_->items);
const std::string TIME_STR = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10)
+ clock_.separator
+ std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
const std::string TIME_STR = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
// --- Línea 1: vides X - objectes X - temps MM:SS (centrada) ---
const std::string LIVES_LABEL = Locale::get()->get("scoreboard.lives");
@@ -105,9 +103,7 @@ void Scoreboard::fillTexture() {
const std::string TIME_LABEL = Locale::get()->get("scoreboard.time");
// Ancho total: labels proporcionales + valores monoespaciados
const int LINE1_W = text->length(LIVES_LABEL) + text->lengthMono(LIVES_STR, MONO_W)
+ text->length(SEP) + text->length(ITEMS_LABEL) + text->lengthMono(ITEMS_STR, MONO_W)
+ text->length(SEP) + text->length(TIME_LABEL) + text->lengthMono(TIME_STR, MONO_W);
const int LINE1_W = text->length(LIVES_LABEL) + text->lengthMono(LIVES_STR, MONO_W) + text->length(SEP) + text->length(ITEMS_LABEL) + text->lengthMono(ITEMS_STR, MONO_W) + text->length(SEP) + text->length(TIME_LABEL) + text->lengthMono(TIME_STR, MONO_W);
int x = (CANVAS_W - LINE1_W) / 2;
text->writeColored(x, LINE1_Y, LIVES_LABEL, LABEL_COLOR);

View File

@@ -92,12 +92,12 @@ class TilemapRenderer {
};
// === 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; // 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)
// === Datos de la habitación ===
std::vector<int> tile_map_; // Índices de tiles de la habitación