migrats els fitxers .room i .tmx a .yaml unificats
This commit is contained in:
@@ -54,9 +54,8 @@ void Room::initializeRoom(const Data& room) {
|
||||
left_room_ = room.left_room;
|
||||
right_room_ = room.right_room;
|
||||
tile_set_file_ = room.tile_set_file;
|
||||
tile_map_file_ = room.tile_map_file;
|
||||
conveyor_belt_direction_ = room.conveyor_belt_direction;
|
||||
tile_map_ = Resource::Cache::get()->getTileMap(room.tile_map_file);
|
||||
tile_map_ = room.tile_map; // Tilemap viene embebido en el YAML
|
||||
surface_ = Resource::Cache::get()->getSurface(room.tile_set_file);
|
||||
tile_set_width_ = surface_->getWidth() / TILE_SIZE;
|
||||
is_paused_ = false;
|
||||
@@ -257,12 +256,7 @@ auto Room::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* {
|
||||
return collision_map_->getSlopeAtPoint(p);
|
||||
}
|
||||
|
||||
// Carga las variables desde un fichero de mapa (delegado a RoomLoader)
|
||||
auto Room::loadRoomFile(const std::string& file_path, bool verbose) -> Data {
|
||||
return RoomLoader::loadRoomFile(file_path, verbose);
|
||||
}
|
||||
|
||||
// Carga las variables y texturas desde un fichero de mapa de tiles (delegado a RoomLoader)
|
||||
auto Room::loadRoomTileFile(const std::string& file_path, bool verbose) -> std::vector<int> {
|
||||
return RoomLoader::loadRoomTileFile(file_path, verbose);
|
||||
// Carga una habitación desde un archivo YAML (delegado a RoomLoader)
|
||||
auto Room::loadYAML(const std::string& file_path, bool verbose) -> Data {
|
||||
return RoomLoader::loadYAML(file_path, verbose);
|
||||
}
|
||||
|
||||
@@ -49,9 +49,8 @@ class Room {
|
||||
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
|
||||
std::string tile_map_file{}; // Fichero con el mapa de índices de tile
|
||||
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
|
||||
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
|
||||
};
|
||||
@@ -93,9 +92,8 @@ class Room {
|
||||
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
|
||||
|
||||
// Métodos de carga de archivos (delegados a RoomLoader)
|
||||
static auto loadRoomFile(const std::string& file_path, bool verbose = false) -> Data; // Carga las variables desde un fichero de mapa
|
||||
static auto loadRoomTileFile(const std::string& file_path, bool verbose = false) -> std::vector<int>; // Carga las variables y texturas desde un fichero de mapa de tiles
|
||||
// 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
|
||||
|
||||
private:
|
||||
// Constantes
|
||||
@@ -123,8 +121,7 @@ class Room {
|
||||
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::string tile_map_file_; // Fichero con el mapa de indices de tile
|
||||
std::vector<int> tile_map_; // Indice de los tiles a dibujar en la habitación
|
||||
std::vector<int> 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
|
||||
|
||||
@@ -2,297 +2,296 @@
|
||||
|
||||
#include <exception> // Para exception
|
||||
#include <iostream> // Para cout, cerr
|
||||
#include <sstream> // Para istringstream, stringstream
|
||||
#include <yaml-cpp/yaml.h> // Para YAML::Node, YAML::LoadFile
|
||||
|
||||
#include "core/resources/resource_helper.hpp" // Para Resource::Helper
|
||||
#include "utils/defines.hpp" // Para TILE_SIZE
|
||||
#include "utils/utils.hpp" // Para stringToBool, stringToColor
|
||||
#include "utils/utils.hpp" // Para stringToColor
|
||||
|
||||
// Asigna variables a una estructura RoomData
|
||||
auto RoomLoader::setRoom(Room::Data& room, const std::string& key, const std::string& value) -> bool {
|
||||
// Indicador de éxito en la asignación
|
||||
bool success = true;
|
||||
|
||||
try {
|
||||
if (key == "tileMapFile") {
|
||||
room.tile_map_file = value;
|
||||
} else if (key == "name") {
|
||||
room.name = value;
|
||||
} else if (key == "bgColor") {
|
||||
room.bg_color = value;
|
||||
} else if (key == "border") {
|
||||
room.border_color = value;
|
||||
} else if (key == "itemColor1") {
|
||||
room.item_color1 = value;
|
||||
} else if (key == "itemColor2") {
|
||||
room.item_color2 = value;
|
||||
} else if (key == "tileSetFile") {
|
||||
room.tile_set_file = value;
|
||||
} else if (key == "roomUp") {
|
||||
room.upper_room = value;
|
||||
} else if (key == "roomDown") {
|
||||
room.lower_room = value;
|
||||
} else if (key == "roomLeft") {
|
||||
room.left_room = value;
|
||||
} else if (key == "roomRight") {
|
||||
room.right_room = value;
|
||||
} else if (key == "autoSurface") {
|
||||
room.conveyor_belt_direction = (value == "right") ? 1 : -1;
|
||||
} else if (key.empty() || key.substr(0, 1) == "#") {
|
||||
// No se realiza ninguna acción para estas claves
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error al asignar la clave " << key << " con valor " << value << ": " << e.what() << '\n';
|
||||
success = false;
|
||||
// Convierte room connection de YAML a formato legacy
|
||||
auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string {
|
||||
if (value == "null" || value.empty()) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
return success;
|
||||
// "02" → "02.room"
|
||||
return value + ".room";
|
||||
}
|
||||
|
||||
// Asigna variables a una estructura EnemyData
|
||||
auto RoomLoader::setEnemy(Enemy::Data& enemy, const std::string& key, const std::string& value) -> bool {
|
||||
// Indicador de éxito en la asignación
|
||||
bool success = true;
|
||||
// Convierte un tilemap 2D a vector 1D flat
|
||||
auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int> {
|
||||
std::vector<int> tilemap_flat;
|
||||
tilemap_flat.reserve(512); // 16 rows × 32 cols
|
||||
|
||||
try {
|
||||
if (key == "animation") {
|
||||
enemy.animation_path = value;
|
||||
} else if (key == "x") {
|
||||
enemy.x = std::stof(value) * TILE_SIZE;
|
||||
} else if (key == "y") {
|
||||
enemy.y = std::stof(value) * TILE_SIZE;
|
||||
} else if (key == "vx") {
|
||||
enemy.vx = std::stof(value);
|
||||
} else if (key == "vy") {
|
||||
enemy.vy = std::stof(value);
|
||||
} else if (key == "x1") {
|
||||
enemy.x1 = std::stoi(value) * TILE_SIZE;
|
||||
} else if (key == "x2") {
|
||||
enemy.x2 = std::stoi(value) * TILE_SIZE;
|
||||
} else if (key == "y1") {
|
||||
enemy.y1 = std::stoi(value) * TILE_SIZE;
|
||||
} else if (key == "y2") {
|
||||
enemy.y2 = std::stoi(value) * TILE_SIZE;
|
||||
} else if (key == "flip") {
|
||||
enemy.flip = stringToBool(value);
|
||||
} else if (key == "mirror") {
|
||||
enemy.mirror = stringToBool(value);
|
||||
} else if (key == "color") {
|
||||
enemy.color = value;
|
||||
} else if (key == "frame") {
|
||||
enemy.frame = std::stoi(value);
|
||||
} else if (key == "[/enemy]" || key == "tileSetFile" || key.substr(0, 1) == "#") {
|
||||
// No se realiza ninguna acción para estas claves
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error al asignar la clave " << key << " con valor " << value << ": " << e.what() << '\n';
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Asigna variables a una estructura ItemData
|
||||
auto RoomLoader::setItem(Item::Data& item, const std::string& key, const std::string& value) -> bool {
|
||||
// Indicador de éxito en la asignación
|
||||
bool success = true;
|
||||
|
||||
try {
|
||||
if (key == "tileSetFile") {
|
||||
item.tile_set_file = value;
|
||||
} else if (key == "counter") {
|
||||
item.counter = std::stoi(value);
|
||||
} else if (key == "x") {
|
||||
item.x = std::stof(value) * TILE_SIZE;
|
||||
} else if (key == "y") {
|
||||
item.y = std::stof(value) * TILE_SIZE;
|
||||
} else if (key == "tile") {
|
||||
item.tile = std::stof(value);
|
||||
} else if (key == "[/item]") {
|
||||
// No se realiza ninguna acción para esta clave
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error al asignar la clave " << key << " con valor " << value << ": " << e.what() << '\n';
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Carga las variables y texturas desde un fichero de mapa de tiles
|
||||
auto RoomLoader::loadRoomTileFile(const std::string& file_path, bool verbose) -> std::vector<int> {
|
||||
std::vector<int> tile_map_file;
|
||||
const std::string FILENAME = file_path.substr(file_path.find_last_of("\\/") + 1);
|
||||
|
||||
// Load file using ResourceHelper (supports both filesystem and pack)
|
||||
auto file_data = Resource::Helper::loadFile(file_path);
|
||||
|
||||
if (!file_data.empty()) {
|
||||
// Convert bytes to string and parse
|
||||
std::string content(file_data.begin(), file_data.end());
|
||||
std::istringstream stream(content);
|
||||
std::string line;
|
||||
|
||||
// Procesa el fichero linea a linea
|
||||
while (std::getline(stream, line)) { // Lee el fichero linea a linea
|
||||
if (line.find("data encoding") != std::string::npos) {
|
||||
// Lee la primera linea
|
||||
std::getline(stream, line);
|
||||
// Trim line to handle Windows line endings
|
||||
line.erase(0, line.find_first_not_of(" \t\r\n"));
|
||||
line.erase(line.find_last_not_of(" \t\r\n") + 1);
|
||||
while (line != "</data>") { // Procesa lineas mientras haya
|
||||
std::stringstream ss(line);
|
||||
std::string tmp;
|
||||
while (getline(ss, tmp, ',')) {
|
||||
// Trim whitespace (including \r, \n, spaces, tabs)
|
||||
tmp.erase(0, tmp.find_first_not_of(" \t\r\n"));
|
||||
tmp.erase(tmp.find_last_not_of(" \t\r\n") + 1);
|
||||
|
||||
// Skip empty strings (from trailing commas)
|
||||
if (!tmp.empty()) {
|
||||
tile_map_file.push_back(std::stoi(tmp) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Lee la siguiente linea
|
||||
std::getline(stream, line);
|
||||
// Trim line to handle Windows line endings
|
||||
line.erase(0, line.find_first_not_of(" \t\r\n"));
|
||||
line.erase(line.find_last_not_of(" \t\r\n") + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "TileMap loaded: " << FILENAME.c_str() << '\n';
|
||||
}
|
||||
} else { // El fichero no se puede abrir
|
||||
if (verbose) {
|
||||
std::cout << "Warning: Unable to open " << FILENAME.c_str() << " file" << '\n';
|
||||
for (const auto& row : tilemap_2d) {
|
||||
for (int tile : row) {
|
||||
tilemap_flat.push_back(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return tile_map_file;
|
||||
return tilemap_flat;
|
||||
}
|
||||
|
||||
// Carga las variables desde un fichero de mapa
|
||||
auto RoomLoader::loadRoomFile(const std::string& file_path, bool verbose) -> Room::Data {
|
||||
// Carga un archivo de room en formato YAML
|
||||
auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data {
|
||||
Room::Data room;
|
||||
room.item_color1 = "yellow";
|
||||
room.item_color2 = "magenta";
|
||||
room.conveyor_belt_direction = 1;
|
||||
|
||||
// Extract filename for logging
|
||||
const std::string FILE_NAME = file_path.substr(file_path.find_last_of("\\/") + 1);
|
||||
room.number = FILE_NAME.substr(0, FILE_NAME.find_last_of('.'));
|
||||
|
||||
// Load file using ResourceHelper (supports both filesystem and pack)
|
||||
auto file_data = Resource::Helper::loadFile(file_path);
|
||||
try {
|
||||
// Load YAML file using ResourceHelper (supports both filesystem and pack)
|
||||
auto file_data = Resource::Helper::loadFile(file_path);
|
||||
|
||||
if (!file_data.empty()) {
|
||||
// Convert bytes to string and parse
|
||||
std::string content(file_data.begin(), file_data.end());
|
||||
std::istringstream stream(content);
|
||||
std::string line;
|
||||
if (file_data.empty()) {
|
||||
std::cerr << "Error: Unable to load file " << FILE_NAME << '\n';
|
||||
return room;
|
||||
}
|
||||
|
||||
// Procesa el fichero linea a linea
|
||||
while (std::getline(stream, line)) {
|
||||
// Remove Windows line ending if present
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
// Parse YAML from string
|
||||
std::string yaml_content(file_data.begin(), file_data.end());
|
||||
YAML::Node yaml = YAML::Load(yaml_content);
|
||||
|
||||
// --- Parse room configuration ---
|
||||
if (yaml["room"]) {
|
||||
const YAML::Node& room_node = yaml["room"];
|
||||
|
||||
// Extract room number from filename (e.g., "01.yaml" → "01")
|
||||
room.number = FILE_NAME.substr(0, FILE_NAME.find_last_of('.'));
|
||||
|
||||
// Basic properties
|
||||
if (room_node["name"]) {
|
||||
room.name = room_node["name"].as<std::string>();
|
||||
}
|
||||
// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
|
||||
if (line == "[enemy]") {
|
||||
room.enemies.push_back(loadEnemyFromFile(stream, FILE_NAME, verbose));
|
||||
if (room_node["bgColor"]) {
|
||||
room.bg_color = room_node["bgColor"].as<std::string>();
|
||||
}
|
||||
// Si la linea contiene el texto [item] se realiza el proceso de carga de un item
|
||||
else if (line == "[item]") {
|
||||
room.items.push_back(loadItemFromFile(stream, FILE_NAME, verbose));
|
||||
if (room_node["border"]) {
|
||||
room.border_color = room_node["border"].as<std::string>();
|
||||
}
|
||||
// En caso contrario se parsea el fichero para buscar las variables y los valores
|
||||
else {
|
||||
auto [key, value] = parseKeyValue(line);
|
||||
if (!setRoom(room, key, value)) {
|
||||
logUnknownParameter(FILE_NAME, key, verbose);
|
||||
if (room_node["tileSetFile"]) {
|
||||
room.tile_set_file = room_node["tileSetFile"].as<std::string>();
|
||||
}
|
||||
|
||||
// Room connections
|
||||
if (room_node["connections"]) {
|
||||
const YAML::Node& conn = room_node["connections"];
|
||||
|
||||
if (conn["up"]) {
|
||||
room.upper_room = convertRoomConnection(conn["up"].as<std::string>("null"));
|
||||
} else {
|
||||
room.upper_room = "0";
|
||||
}
|
||||
|
||||
if (conn["down"]) {
|
||||
room.lower_room = convertRoomConnection(conn["down"].as<std::string>("null"));
|
||||
} else {
|
||||
room.lower_room = "0";
|
||||
}
|
||||
|
||||
if (conn["left"]) {
|
||||
room.left_room = convertRoomConnection(conn["left"].as<std::string>("null"));
|
||||
} else {
|
||||
room.left_room = "0";
|
||||
}
|
||||
|
||||
if (conn["right"]) {
|
||||
room.right_room = convertRoomConnection(conn["right"].as<std::string>("null"));
|
||||
} else {
|
||||
room.right_room = "0";
|
||||
}
|
||||
}
|
||||
|
||||
// Item colors
|
||||
if (room_node["itemColor1"]) {
|
||||
room.item_color1 = room_node["itemColor1"].as<std::string>("yellow");
|
||||
} else {
|
||||
room.item_color1 = "yellow";
|
||||
}
|
||||
|
||||
if (room_node["itemColor2"]) {
|
||||
room.item_color2 = room_node["itemColor2"].as<std::string>("magenta");
|
||||
} else {
|
||||
room.item_color2 = "magenta";
|
||||
}
|
||||
|
||||
// Conveyor belt direction
|
||||
if (room_node["autoSurface"]) {
|
||||
room.conveyor_belt_direction = room_node["autoSurface"].as<int>(0);
|
||||
} else {
|
||||
room.conveyor_belt_direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Parse tilemap ---
|
||||
if (yaml["tilemap"]) {
|
||||
const YAML::Node& tilemap_node = yaml["tilemap"];
|
||||
|
||||
// Read 2D array
|
||||
std::vector<std::vector<int>> tilemap_2d;
|
||||
tilemap_2d.reserve(16);
|
||||
|
||||
for (const auto& row_node : tilemap_node) {
|
||||
std::vector<int> row;
|
||||
row.reserve(32);
|
||||
|
||||
for (const auto& tile_node : row_node) {
|
||||
row.push_back(tile_node.as<int>());
|
||||
}
|
||||
|
||||
tilemap_2d.push_back(row);
|
||||
}
|
||||
|
||||
// Convert to 1D flat array
|
||||
room.tile_map = flattenTilemap(tilemap_2d);
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "Loaded tilemap: " << room.tile_map.size() << " tiles\n";
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Warning: No tilemap found in " << FILE_NAME << '\n';
|
||||
}
|
||||
|
||||
// --- Parse enemies ---
|
||||
if (yaml["enemies"] && !yaml["enemies"].IsNull()) {
|
||||
const YAML::Node& enemies_node = yaml["enemies"];
|
||||
|
||||
for (const auto& enemy_node : enemies_node) {
|
||||
Enemy::Data enemy;
|
||||
|
||||
// Animation path
|
||||
if (enemy_node["animation"]) {
|
||||
enemy.animation_path = enemy_node["animation"].as<std::string>();
|
||||
}
|
||||
|
||||
// Position (in tiles, convert to pixels)
|
||||
if (enemy_node["position"]) {
|
||||
const YAML::Node& pos = enemy_node["position"];
|
||||
if (pos["x"]) {
|
||||
enemy.x = pos["x"].as<float>() * TILE_SIZE;
|
||||
}
|
||||
if (pos["y"]) {
|
||||
enemy.y = pos["y"].as<float>() * TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Velocity (already in pixels/second)
|
||||
if (enemy_node["velocity"]) {
|
||||
const YAML::Node& vel = enemy_node["velocity"];
|
||||
if (vel["x"]) {
|
||||
enemy.vx = vel["x"].as<float>();
|
||||
}
|
||||
if (vel["y"]) {
|
||||
enemy.vy = vel["y"].as<float>();
|
||||
}
|
||||
}
|
||||
|
||||
// Boundaries (in tiles, convert to pixels)
|
||||
if (enemy_node["boundaries"]) {
|
||||
const YAML::Node& bounds = enemy_node["boundaries"];
|
||||
if (bounds["x1"]) {
|
||||
enemy.x1 = bounds["x1"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["y1"]) {
|
||||
enemy.y1 = bounds["y1"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["x2"]) {
|
||||
enemy.x2 = bounds["x2"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
if (bounds["y2"]) {
|
||||
enemy.y2 = bounds["y2"].as<int>() * TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Color
|
||||
if (enemy_node["color"]) {
|
||||
enemy.color = enemy_node["color"].as<std::string>("white");
|
||||
} else {
|
||||
enemy.color = "white";
|
||||
}
|
||||
|
||||
// Optional fields
|
||||
if (enemy_node["flip"]) {
|
||||
enemy.flip = enemy_node["flip"].as<bool>(false);
|
||||
} else {
|
||||
enemy.flip = false;
|
||||
}
|
||||
|
||||
if (enemy_node["mirror"]) {
|
||||
enemy.mirror = enemy_node["mirror"].as<bool>(false);
|
||||
} else {
|
||||
enemy.mirror = false;
|
||||
}
|
||||
|
||||
if (enemy_node["frame"]) {
|
||||
enemy.frame = enemy_node["frame"].as<int>(-1);
|
||||
} else {
|
||||
enemy.frame = -1;
|
||||
}
|
||||
|
||||
room.enemies.push_back(enemy);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "Loaded " << room.enemies.size() << " enemies\n";
|
||||
}
|
||||
}
|
||||
|
||||
// --- Parse items ---
|
||||
if (yaml["items"] && !yaml["items"].IsNull()) {
|
||||
const YAML::Node& items_node = yaml["items"];
|
||||
|
||||
for (const auto& item_node : items_node) {
|
||||
Item::Data item;
|
||||
|
||||
// Tileset file
|
||||
if (item_node["tileSetFile"]) {
|
||||
item.tile_set_file = item_node["tileSetFile"].as<std::string>();
|
||||
}
|
||||
|
||||
// Tile index
|
||||
if (item_node["tile"]) {
|
||||
item.tile = item_node["tile"].as<int>();
|
||||
}
|
||||
|
||||
// Position (in tiles, convert to pixels)
|
||||
if (item_node["position"]) {
|
||||
const YAML::Node& pos = item_node["position"];
|
||||
if (pos["x"]) {
|
||||
item.x = pos["x"].as<float>() * TILE_SIZE;
|
||||
}
|
||||
if (pos["y"]) {
|
||||
item.y = pos["y"].as<float>() * TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Counter
|
||||
if (item_node["counter"]) {
|
||||
item.counter = item_node["counter"].as<int>(0);
|
||||
} else {
|
||||
item.counter = 0;
|
||||
}
|
||||
|
||||
// Colors (assigned from room defaults)
|
||||
item.color1 = stringToColor(room.item_color1);
|
||||
item.color2 = stringToColor(room.item_color2);
|
||||
|
||||
room.items.push_back(item);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "Loaded " << room.items.size() << " items\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "Room loaded: " << FILE_NAME.c_str() << '\n';
|
||||
std::cout << "Room loaded successfully: " << FILE_NAME << '\n';
|
||||
}
|
||||
} else { // El fichero no se puede abrir
|
||||
std::cout << "Warning: Unable to open " << FILE_NAME.c_str() << " file" << '\n';
|
||||
|
||||
} catch (const YAML::Exception& e) {
|
||||
std::cerr << "YAML parsing error in " << FILE_NAME << ": " << e.what() << '\n';
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error loading room " << FILE_NAME << ": " << e.what() << '\n';
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
// Parsea una línea en key y value separados por '='
|
||||
auto RoomLoader::parseKeyValue(const std::string& line) -> std::pair<std::string, std::string> {
|
||||
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 RoomLoader::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() << "\"" << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Carga un bloque [enemy]...[/enemy] desde un archivo
|
||||
auto RoomLoader::loadEnemyFromFile(std::istream& file, const std::string& file_name, bool verbose) -> Enemy::Data {
|
||||
Enemy::Data enemy;
|
||||
enemy.flip = false;
|
||||
enemy.mirror = false;
|
||||
enemy.frame = -1;
|
||||
|
||||
std::string line;
|
||||
do {
|
||||
std::getline(file, line);
|
||||
// Remove Windows line ending if present
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
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
|
||||
auto RoomLoader::loadItemFromFile(std::istream& file, const std::string& file_name, bool verbose) -> Item::Data {
|
||||
Item::Data item;
|
||||
item.counter = 0;
|
||||
item.color1 = stringToColor("yellow");
|
||||
item.color2 = stringToColor("magenta");
|
||||
|
||||
std::string line;
|
||||
do {
|
||||
std::getline(file, line);
|
||||
// Remove Windows line ending if present
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
auto [key, value] = parseKeyValue(line);
|
||||
|
||||
if (!setItem(item, key, value)) {
|
||||
logUnknownParameter(file_name, key, verbose);
|
||||
}
|
||||
} while (line != "[/item]");
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <istream> // Para istream
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para pair
|
||||
#include <vector> // Para vector
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
||||
#include "game/entities/item.hpp" // Para Item::Data
|
||||
#include "game/gameplay/room.hpp" // Para Room::Data
|
||||
|
||||
/**
|
||||
* @brief Cargador de archivos de habitaciones
|
||||
* @brief Cargador de archivos de habitaciones en formato YAML
|
||||
*
|
||||
* Responsabilidades:
|
||||
* - Cargar archivos de room (.room)
|
||||
* - Cargar archivos de tilemap (.tmx)
|
||||
* - Parsear datos de room, enemy e item
|
||||
* - Validar y convertir valores de configuración
|
||||
* - Cargar archivos de room en formato YAML unificado (.yaml)
|
||||
* - Parsear datos de room, tilemap, enemies e items
|
||||
* - Convertir tipos de datos (tiles, posiciones, colores)
|
||||
* - Validar y propagar errores de carga
|
||||
*
|
||||
* Esta clase contiene solo métodos estáticos y no debe instanciarse.
|
||||
*/
|
||||
@@ -31,86 +29,35 @@ class RoomLoader {
|
||||
auto operator=(RoomLoader&&) -> RoomLoader& = delete;
|
||||
|
||||
/**
|
||||
* @brief Carga un archivo de room (.room)
|
||||
* @param file_path Ruta al archivo de room
|
||||
* @brief Carga un archivo de room en formato YAML
|
||||
* @param file_path Ruta al archivo YAML de habitación
|
||||
* @param verbose Si true, muestra información de debug
|
||||
* @return Room::Data con todos los datos de la habitación
|
||||
* @return Room::Data con todos los datos de la habitación incluyendo:
|
||||
* - Configuración de la habitación (nombre, colores, etc.)
|
||||
* - Tilemap completo (convertido de 2D a 1D)
|
||||
* - Lista de enemigos con todas sus propiedades
|
||||
* - Lista de items con todas sus propiedades
|
||||
*
|
||||
* Parsea un archivo .room que contiene:
|
||||
* - Variables de configuración (name, colors, borders, etc.)
|
||||
* - Bloques [enemy]...[/enemy] con datos de enemigos
|
||||
* - Bloques [item]...[/item] con datos de items
|
||||
* El formato YAML esperado incluye:
|
||||
* - room: configuración general
|
||||
* - tilemap: array 2D de 16x32 tiles (convertido a vector 1D de 512 elementos)
|
||||
* - enemies: lista de enemigos (opcional)
|
||||
* - items: lista de items (opcional)
|
||||
*/
|
||||
static auto loadRoomFile(const std::string& file_path, bool verbose = false) -> Room::Data;
|
||||
|
||||
/**
|
||||
* @brief Carga un archivo de tilemap (.tmx)
|
||||
* @param file_path Ruta al archivo de tilemap
|
||||
* @param verbose Si true, muestra información de debug
|
||||
* @return Vector de índices de tiles
|
||||
*
|
||||
* Parsea un archivo .tmx en formato CSV generado por Tiled
|
||||
*/
|
||||
static auto loadRoomTileFile(const std::string& file_path, bool verbose = false) -> std::vector<int>;
|
||||
static auto loadYAML(const std::string& file_path, bool verbose = false) -> Room::Data;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Asigna valores a una estructura Room::Data
|
||||
* @param room Estructura a modificar
|
||||
* @param key Nombre de la variable
|
||||
* @param value Valor a asignar
|
||||
* @return true si la variable fue reconocida y asignada, false si no
|
||||
* @brief Convierte room connection de YAML a formato legacy
|
||||
* @param value Valor del YAML (null o "02")
|
||||
* @return String en formato legacy ("0" para null, "02.room" para "02")
|
||||
*/
|
||||
static auto setRoom(Room::Data& room, const std::string& key, const std::string& value) -> bool;
|
||||
static auto convertRoomConnection(const std::string& value) -> std::string;
|
||||
|
||||
/**
|
||||
* @brief Asigna valores a una estructura Enemy::Data
|
||||
* @param enemy Estructura a modificar
|
||||
* @param key Nombre de la variable
|
||||
* @param value Valor a asignar
|
||||
* @return true si la variable fue reconocida y asignada, false si no
|
||||
* @brief Convierte un tilemap 2D a vector 1D flat
|
||||
* @param tilemap_2d Array 2D de tiles (16 rows × 32 cols)
|
||||
* @return Vector 1D flat con 512 elementos
|
||||
*/
|
||||
static auto setEnemy(Enemy::Data& enemy, const std::string& key, const std::string& value) -> bool;
|
||||
|
||||
/**
|
||||
* @brief Asigna valores a una estructura Item::Data
|
||||
* @param item Estructura a modificar
|
||||
* @param key Nombre de la variable
|
||||
* @param value Valor a asignar
|
||||
* @return true si la variable fue reconocida y asignada, false si no
|
||||
*/
|
||||
static auto setItem(Item::Data& item, const std::string& key, const std::string& value) -> bool;
|
||||
|
||||
/**
|
||||
* @brief Parsea una línea en formato "key=value"
|
||||
* @param line Línea a parsear
|
||||
* @return Par {key, value}. Si no hay '=', devuelve {"", ""}
|
||||
*/
|
||||
static auto parseKeyValue(const std::string& line) -> std::pair<std::string, std::string>;
|
||||
|
||||
/**
|
||||
* @brief Registra un parámetro desconocido en la consola
|
||||
* @param file_name Nombre del archivo siendo parseado
|
||||
* @param key Nombre del parámetro desconocido
|
||||
* @param verbose Si true, muestra el mensaje
|
||||
*/
|
||||
static void logUnknownParameter(const std::string& file_name, const std::string& key, bool verbose);
|
||||
|
||||
/**
|
||||
* @brief Carga un bloque [enemy]...[/enemy] desde un stream
|
||||
* @param file Stream del archivo
|
||||
* @param file_name Nombre del archivo (para debug)
|
||||
* @param verbose Si true, muestra información de debug
|
||||
* @return Enemy::Data con los datos del enemigo
|
||||
*/
|
||||
static auto loadEnemyFromFile(std::istream& file, const std::string& file_name, bool verbose) -> Enemy::Data;
|
||||
|
||||
/**
|
||||
* @brief Carga un bloque [item]...[/item] desde un stream
|
||||
* @param file Stream del archivo
|
||||
* @param file_name Nombre del archivo (para debug)
|
||||
* @param verbose Si true, muestra información de debug
|
||||
* @return Item::Data con los datos del item
|
||||
*/
|
||||
static auto loadItemFromFile(std::istream& file, const std::string& file_name, bool verbose) -> Item::Data;
|
||||
static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user