This commit is contained in:
2025-10-27 17:39:23 +01:00
parent aacb14149f
commit b1dca32a5b
18 changed files with 774 additions and 565 deletions

View File

@@ -1,5 +1,6 @@
#include "game/gameplay/room.hpp"
#include <algorithm> // Para std::ranges::any_of
#include <exception> // Para exception
#include <fstream> // Para basic_ostream, operator<<, basic_istream
#include <iostream> // Para cout, cerr
@@ -60,6 +61,61 @@ std::vector<int> loadRoomTileFile(const std::string& file_path, bool verbose) {
return tile_map_file;
}
// Parsea una línea en key y value separados por '='
std::pair<std::string, std::string> parseKeyValue(const std::string& line) {
int pos = line.find("=");
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1, line.length());
return {key, value};
}
// Muestra un warning de parámetro desconocido
void logUnknownParameter(const std::string& file_name, const std::string& key, bool verbose) {
if (verbose) {
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << key.c_str() << "\"" << std::endl;
}
}
// Carga un bloque [enemy]...[/enemy] desde un archivo
EnemyData loadEnemyFromFile(std::ifstream& file, const std::string& file_name, bool verbose) {
EnemyData enemy;
enemy.flip = false;
enemy.mirror = false;
enemy.frame = -1;
std::string line;
do {
std::getline(file, line);
auto [key, value] = parseKeyValue(line);
if (!setEnemy(&enemy, key, value)) {
logUnknownParameter(file_name, key, verbose);
}
} while (line != "[/enemy]");
return enemy;
}
// Carga un bloque [item]...[/item] desde un archivo
ItemData loadItemFromFile(std::ifstream& file, const std::string& file_name, bool verbose) {
ItemData item;
item.counter = 0;
item.color1 = stringToColor("yellow");
item.color2 = stringToColor("magenta");
std::string line;
do {
std::getline(file, line);
auto [key, value] = parseKeyValue(line);
if (!setItem(&item, key, value)) {
logUnknownParameter(file_name, key, verbose);
}
} while (line != "[/item]");
return item;
}
// Carga las variables desde un fichero de mapa
RoomData loadRoomFile(const std::string& file_path, bool verbose) {
RoomData room;
@@ -79,70 +135,17 @@ RoomData loadRoomFile(const std::string& file_path, bool verbose) {
while (std::getline(file, line)) {
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
if (line == "[enemy]") {
EnemyData enemy;
enemy.flip = false;
enemy.mirror = false;
enemy.frame = -1;
do {
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1, line.length());
if (!setEnemy(&enemy, key, value)) {
if (verbose) {
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
}
} while (line != "[/enemy]");
// Añade el enemigo al vector de enemigos
room.enemies.push_back(enemy);
room.enemies.push_back(loadEnemyFromFile(file, FILE_NAME, verbose));
}
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
else if (line == "[item]") {
ItemData item;
item.counter = 0;
item.color1 = stringToColor("yellow");
item.color2 = stringToColor("magenta");
do {
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1, line.length());
if (!setItem(&item, key, value)) {
if (verbose) {
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
}
} while (line != "[/item]");
room.items.push_back(item);
room.items.push_back(loadItemFromFile(file, FILE_NAME, verbose));
}
// En caso contrario se parsea el fichero para buscar las variables y los valores
else {
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1, line.length());
auto [key, value] = parseKeyValue(line);
if (!setRoom(&room, key, value)) {
if (verbose) {
std::cout << "Warning: file " << FILE_NAME.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
logUnknownParameter(FILE_NAME, key, verbose);
}
}
}
@@ -155,9 +158,7 @@ RoomData loadRoomFile(const std::string& file_path, bool verbose) {
}
// El fichero no se puede abrir
else {
{
std::cout << "Warning: Unable to open " << FILE_NAME.c_str() << " file" << std::endl;
}
std::cout << "Warning: Unable to open " << FILE_NAME.c_str() << " file" << std::endl;
}
return room;
@@ -555,7 +556,7 @@ TileType Room::getTile(int index) {
}
// La fila 23 es de tiles t_kill
else if ((tile_map_[index] >= 23 * tile_set_width_) && (tile_map_[index] < 24 * tile_set_width_)) {
if ((tile_map_[index] >= 23 * tile_set_width_) && (tile_map_[index] < 24 * tile_set_width_)) {
return TileType::KILL;
}
}
@@ -565,12 +566,9 @@ TileType Room::getTile(int index) {
// Indica si hay colision con un enemigo a partir de un rectangulo
bool Room::enemyCollision(SDL_FRect& rect) {
for (const auto& enemy : enemies_) {
if (checkCollision(rect, enemy->getCollider())) {
return true;
}
}
return false;
return std::ranges::any_of(enemies_, [&rect](const auto& enemy) {
return checkCollision(rect, enemy->getCollider());
});
}
// Indica si hay colision con un objeto a partir de un rectangulo
@@ -619,8 +617,8 @@ int Room::getSlopeHeight(SDL_FPoint p, TileType slope) {
return base;
}
// Calcula las superficies inferiores
void Room::setBottomSurfaces() {
// Helper: recopila tiles inferiores (muros sin muro debajo)
std::vector<int> Room::collectBottomTiles() {
std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tengan debajo otro muro
@@ -638,40 +636,11 @@ void Room::setBottomSurfaces() {
// Añade un terminador
tile.push_back(-1);
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
if ((int)tile.size() > 1) {
int i = 0;
do {
LineHorizontal line;
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
line.y = ((tile[i] / MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
int last_one = i;
i++;
if (i <= (int)tile.size() - 1) {
while (tile[i] == tile[i - 1] + 1) {
last_one = i;
if (i == (int)tile.size() - 1) {
break;
}
i++;
}
}
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
bottom_floors_.push_back(line);
if (i <= (int)tile.size() - 1) {
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
} while (i < (int)tile.size() - 1);
}
return tile;
}
// Calcula las superficies superiores
void Room::setTopSurfaces() {
// Helper: recopila tiles superiores (muros o pasables sin muro encima)
std::vector<int> Room::collectTopTiles() {
std::vector<int> tile;
// Busca todos los tiles de tipo muro o pasable que no tengan encima un muro
@@ -689,36 +658,61 @@ void Room::setTopSurfaces() {
// Añade un terminador
tile.push_back(-1);
return tile;
}
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
if ((int)tile.size() > 1) {
int i = 0;
do {
LineHorizontal line;
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
line.y = (tile[i] / MAP_WIDTH) * TILE_SIZE;
int last_one = i;
i++;
if (i <= (int)tile.size() - 1) {
while (tile[i] == tile[i - 1] + 1) {
last_one = i;
if (i == (int)tile.size() - 1) {
break;
}
i++;
}
}
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
top_floors_.push_back(line);
if (i <= (int)tile.size() - 1) {
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
} while (i < (int)tile.size() - 1);
// Helper: construye lineas horizontales a partir de tiles consecutivos
void Room::buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface) {
if (tiles.size() <= 1) {
return;
}
int i = 0;
while (i < (int)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 < (int)tiles.size()) {
while (tiles[i] == tiles[i - 1] + 1) {
last_one = i;
i++;
if (i >= (int)tiles.size()) {
break;
}
}
}
line.x2 = ((tiles[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
lines.push_back(line);
// Salta separadores
if (i < (int)tiles.size() && tiles[i] == -1) {
i++;
}
}
}
// Calcula las superficies inferiores
void Room::setBottomSurfaces() {
std::vector<int> tile = collectBottomTiles();
buildHorizontalLines(tile, bottom_floors_, true);
}
// Calcula las superficies superiores
void Room::setTopSurfaces() {
std::vector<int> tile = collectTopTiles();
buildHorizontalLines(tile, top_floors_, false);
}
// Calcula las superficies laterales izquierdas
@@ -872,7 +866,8 @@ void Room::setRightSlopes() {
}
// Calcula las superficies automaticas
void Room::setAutoSurfaces() {
// Helper: recopila tiles animados (para superficies automaticas/conveyor belts)
std::vector<int> Room::collectAnimatedTiles() {
std::vector<int> tile;
// Busca todos los tiles de tipo animado
@@ -888,35 +883,17 @@ void Room::setAutoSurfaces() {
}
}
// Recorre el vector de tiles buscando tiles consecutivos para localizar las superficies
if ((int)tile.size() > 0) {
int i = 0;
do {
LineHorizontal line;
line.x1 = (tile[i] % MAP_WIDTH) * TILE_SIZE;
line.y = (tile[i] / MAP_WIDTH) * TILE_SIZE;
int last_one = i;
i++;
if (i <= (int)tile.size() - 1) {
while (tile[i] == tile[i - 1] + 1) {
last_one = i;
if (i == (int)tile.size() - 1) {
break;
}
i++;
}
}
line.x2 = ((tile[last_one] % MAP_WIDTH) * TILE_SIZE) + TILE_SIZE - 1;
conveyor_belt_floors_.push_back(line);
if (i <= (int)tile.size() - 1) {
if (tile[i] == -1) { // Si el siguiente elemento es un separador, hay que saltarlo
i++;
}
}
} while (i < (int)tile.size() - 1);
// Añade un terminador si hay tiles
if (!tile.empty()) {
tile.push_back(-1);
}
return tile;
}
void Room::setAutoSurfaces() {
std::vector<int> tile = collectAnimatedTiles();
buildHorizontalLines(tile, conveyor_belt_floors_, false);
}
// Localiza todos los tiles animados de la habitación
@@ -1022,24 +999,16 @@ int Room::checkAutoSurfaces(SDL_FRect* rect) {
// Comprueba las colisiones
bool Room::checkTopSurfaces(SDL_FPoint* p) {
for (const auto& s : top_floors_) {
if (checkCollision(s, *p)) {
return true;
}
}
return false;
return std::ranges::any_of(top_floors_, [&](const auto& s) {
return checkCollision(s, *p);
});
}
// Comprueba las colisiones
bool Room::checkAutoSurfaces(SDL_FPoint* p) {
for (const auto& s : conveyor_belt_floors_) {
if (checkCollision(s, *p)) {
return true;
}
}
return false;
return std::ranges::any_of(conveyor_belt_floors_, [&](const auto& s) {
return checkCollision(s, *p);
});
}
// Comprueba las colisiones
@@ -1056,13 +1025,9 @@ int Room::checkLeftSlopes(const LineVertical* line) {
// Comprueba las colisiones
bool Room::checkLeftSlopes(SDL_FPoint* p) {
for (const auto& slope : left_slopes_) {
if (checkCollision(*p, slope)) {
return true;
}
}
return false;
return std::ranges::any_of(left_slopes_, [&](const auto& slope) {
return checkCollision(*p, slope);
});
}
// Comprueba las colisiones
@@ -1079,13 +1044,9 @@ int Room::checkRightSlopes(const LineVertical* line) {
// Comprueba las colisiones
bool Room::checkRightSlopes(SDL_FPoint* p) {
for (const auto& slope : right_slopes_) {
if (checkCollision(*p, slope)) {
return true;
}
}
return false;
return std::ranges::any_of(right_slopes_, [&](const auto& slope) {
return checkCollision(*p, slope);
});
}
// Abre la Jail si se da el caso