This commit is contained in:
2025-11-21 08:07:32 +01:00
parent 9aa86cd531
commit 0fb986d7c4
16 changed files with 369 additions and 381 deletions

View File

@@ -51,6 +51,267 @@ auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d)
return tilemap_flat;
}
// Parsea la configuración general de la habitación
void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name) {
if (!yaml.contains("room")) {
return;
}
const auto& 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.contains("name")) {
room.name = room_node["name"].get_value<std::string>();
}
if (room_node.contains("bgColor")) {
room.bg_color = room_node["bgColor"].get_value<std::string>();
}
if (room_node.contains("border")) {
room.border_color = room_node["border"].get_value<std::string>();
}
if (room_node.contains("tileSetFile")) {
room.tile_set_file = room_node["tileSetFile"].get_value<std::string>();
}
// Room connections
if (room_node.contains("connections")) {
parseRoomConnections(room_node["connections"], room);
}
// Item colors
room.item_color1 = room_node.contains("itemColor1")
? room_node["itemColor1"].get_value_or<std::string>("yellow")
: "yellow";
room.item_color2 = room_node.contains("itemColor2")
? room_node["itemColor2"].get_value_or<std::string>("magenta")
: "magenta";
// Dirección de la cinta transportadora (left/none/right)
room.conveyor_belt_direction = room_node.contains("conveyorBelt")
? convertAutoSurface(room_node["conveyorBelt"])
: 0;
}
// Parsea las conexiones de la habitación (arriba/abajo/izq/der)
void RoomLoader::parseRoomConnections(const fkyaml::node& conn_node, Room::Data& room) {
room.upper_room = conn_node.contains("up")
? convertRoomConnection(conn_node["up"].get_value_or<std::string>("null"))
: "0";
room.lower_room = conn_node.contains("down")
? convertRoomConnection(conn_node["down"].get_value_or<std::string>("null"))
: "0";
room.left_room = conn_node.contains("left")
? convertRoomConnection(conn_node["left"].get_value_or<std::string>("null"))
: "0";
room.right_room = conn_node.contains("right")
? convertRoomConnection(conn_node["right"].get_value_or<std::string>("null"))
: "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) {
if (!yaml.contains("tilemap")) {
std::cerr << "Warning: No tilemap found in " << file_name << '\n';
return;
}
const auto& 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.get_value<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";
}
}
// Parsea los límites de movimiento de un enemigo
void RoomLoader::parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy) {
// Nuevo formato: position1 y position2
if (bounds_node.contains("position1")) {
const auto& pos1 = bounds_node["position1"];
if (pos1.contains("x")) {
enemy.x1 = pos1["x"].get_value<int>() * TILE_SIZE;
}
if (pos1.contains("y")) {
enemy.y1 = pos1["y"].get_value<int>() * TILE_SIZE;
}
}
if (bounds_node.contains("position2")) {
const auto& pos2 = bounds_node["position2"];
if (pos2.contains("x")) {
enemy.x2 = pos2["x"].get_value<int>() * TILE_SIZE;
}
if (pos2.contains("y")) {
enemy.y2 = pos2["y"].get_value<int>() * TILE_SIZE;
}
}
// Formato antiguo: x1/y1/x2/y2 (compatibilidad)
if (bounds_node.contains("x1")) {
enemy.x1 = bounds_node["x1"].get_value<int>() * TILE_SIZE;
}
if (bounds_node.contains("y1")) {
enemy.y1 = bounds_node["y1"].get_value<int>() * TILE_SIZE;
}
if (bounds_node.contains("x2")) {
enemy.x2 = bounds_node["x2"].get_value<int>() * TILE_SIZE;
}
if (bounds_node.contains("y2")) {
enemy.y2 = bounds_node["y2"].get_value<int>() * TILE_SIZE;
}
}
// Parsea los datos de un enemigo individual
auto RoomLoader::parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data {
Enemy::Data enemy;
// Animation path
if (enemy_node.contains("animation")) {
enemy.animation_path = enemy_node["animation"].get_value<std::string>();
}
// Position (in tiles, convert to pixels)
if (enemy_node.contains("position")) {
const auto& pos = enemy_node["position"];
if (pos.contains("x")) {
enemy.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
enemy.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Velocity (already in pixels/second)
if (enemy_node.contains("velocity")) {
const auto& vel = enemy_node["velocity"];
if (vel.contains("x")) {
enemy.vx = vel["x"].get_value<float>();
}
if (vel.contains("y")) {
enemy.vy = vel["y"].get_value<float>();
}
}
// Boundaries (in tiles, convert to pixels)
if (enemy_node.contains("boundaries")) {
parseEnemyBoundaries(enemy_node["boundaries"], enemy);
}
// Color
enemy.color = enemy_node.contains("color")
? enemy_node["color"].get_value_or<std::string>("white")
: "white";
// Optional fields
enemy.flip = enemy_node.contains("flip")
? enemy_node["flip"].get_value_or<bool>(false)
: false;
enemy.mirror = enemy_node.contains("mirror")
? enemy_node["mirror"].get_value_or<bool>(false)
: false;
enemy.frame = enemy_node.contains("frame")
? enemy_node["frame"].get_value_or<int>(-1)
: -1;
return enemy;
}
// Parsea la lista de enemigos de la habitación
void RoomLoader::parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose) {
if (!yaml.contains("enemies") || yaml["enemies"].is_null()) {
return;
}
const auto& enemies_node = yaml["enemies"];
for (const auto& enemy_node : enemies_node) {
room.enemies.push_back(parseEnemyData(enemy_node));
}
if (verbose) {
std::cout << "Loaded " << room.enemies.size() << " enemies\n";
}
}
// Parsea los datos de un item individual
auto RoomLoader::parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data {
Item::Data item;
// Tileset file
if (item_node.contains("tileSetFile")) {
item.tile_set_file = item_node["tileSetFile"].get_value<std::string>();
}
// Tile index
if (item_node.contains("tile")) {
item.tile = item_node["tile"].get_value<int>();
}
// Position (in tiles, convert to pixels)
if (item_node.contains("position")) {
const auto& pos = item_node["position"];
if (pos.contains("x")) {
item.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
item.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Counter
item.counter = item_node.contains("counter")
? item_node["counter"].get_value_or<int>(0)
: 0;
// Colors (assigned from room defaults)
item.color1 = stringToColor(room.item_color1);
item.color2 = stringToColor(room.item_color2);
return item;
}
// Parsea la lista de items de la habitación
void RoomLoader::parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose) {
if (!yaml.contains("items") || yaml["items"].is_null()) {
return;
}
const auto& items_node = yaml["items"];
for (const auto& item_node : items_node) {
room.items.push_back(parseItemData(item_node, room));
}
if (verbose) {
std::cout << "Loaded " << room.items.size() << " items\n";
}
}
// Carga un archivo de room en formato YAML
auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data {
Room::Data room;
@@ -71,260 +332,11 @@ auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::D
std::string yaml_content(file_data.begin(), file_data.end());
auto yaml = fkyaml::node::deserialize(yaml_content);
// --- Parse room configuration ---
if (yaml.contains("room")) {
const auto& 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.contains("name")) {
room.name = room_node["name"].get_value<std::string>();
}
if (room_node.contains("bgColor")) {
room.bg_color = room_node["bgColor"].get_value<std::string>();
}
if (room_node.contains("border")) {
room.border_color = room_node["border"].get_value<std::string>();
}
if (room_node.contains("tileSetFile")) {
room.tile_set_file = room_node["tileSetFile"].get_value<std::string>();
}
// Room connections
if (room_node.contains("connections")) {
const auto& conn = room_node["connections"];
if (conn.contains("up")) {
room.upper_room = convertRoomConnection(conn["up"].get_value_or<std::string>("null"));
} else {
room.upper_room = "0";
}
if (conn.contains("down")) {
room.lower_room = convertRoomConnection(conn["down"].get_value_or<std::string>("null"));
} else {
room.lower_room = "0";
}
if (conn.contains("left")) {
room.left_room = convertRoomConnection(conn["left"].get_value_or<std::string>("null"));
} else {
room.left_room = "0";
}
if (conn.contains("right")) {
room.right_room = convertRoomConnection(conn["right"].get_value_or<std::string>("null"));
} else {
room.right_room = "0";
}
}
// Item colors
if (room_node.contains("itemColor1")) {
room.item_color1 = room_node["itemColor1"].get_value_or<std::string>("yellow");
} else {
room.item_color1 = "yellow";
}
if (room_node.contains("itemColor2")) {
room.item_color2 = room_node["itemColor2"].get_value_or<std::string>("magenta");
} else {
room.item_color2 = "magenta";
}
// Dirección de la cinta transportadora (left/none/right)
if (room_node.contains("conveyorBelt")) {
room.conveyor_belt_direction = convertAutoSurface(room_node["conveyorBelt"]);
} else {
room.conveyor_belt_direction = 0;
}
}
// --- Parse tilemap ---
if (yaml.contains("tilemap")) {
const auto& 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.get_value<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.contains("enemies") && !yaml["enemies"].is_null()) {
const auto& enemies_node = yaml["enemies"];
for (const auto& enemy_node : enemies_node) {
Enemy::Data enemy;
// Animation path
if (enemy_node.contains("animation")) {
enemy.animation_path = enemy_node["animation"].get_value<std::string>();
}
// Position (in tiles, convert to pixels)
if (enemy_node.contains("position")) {
const auto& pos = enemy_node["position"];
if (pos.contains("x")) {
enemy.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
enemy.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Velocity (already in pixels/second)
if (enemy_node.contains("velocity")) {
const auto& vel = enemy_node["velocity"];
if (vel.contains("x")) {
enemy.vx = vel["x"].get_value<float>();
}
if (vel.contains("y")) {
enemy.vy = vel["y"].get_value<float>();
}
}
// Boundaries (in tiles, convert to pixels)
// Soporta formato nuevo (position1/position2) y antiguo (x1/y1/x2/y2)
if (enemy_node.contains("boundaries")) {
const auto& bounds = enemy_node["boundaries"];
// Nuevo formato: position1 y position2
if (bounds.contains("position1")) {
const auto& pos1 = bounds["position1"];
if (pos1.contains("x")) {
enemy.x1 = pos1["x"].get_value<int>() * TILE_SIZE;
}
if (pos1.contains("y")) {
enemy.y1 = pos1["y"].get_value<int>() * TILE_SIZE;
}
}
if (bounds.contains("position2")) {
const auto& pos2 = bounds["position2"];
if (pos2.contains("x")) {
enemy.x2 = pos2["x"].get_value<int>() * TILE_SIZE;
}
if (pos2.contains("y")) {
enemy.y2 = pos2["y"].get_value<int>() * TILE_SIZE;
}
}
// Formato antiguo: x1/y1/x2/y2 (compatibilidad)
if (bounds.contains("x1")) {
enemy.x1 = bounds["x1"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("y1")) {
enemy.y1 = bounds["y1"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("x2")) {
enemy.x2 = bounds["x2"].get_value<int>() * TILE_SIZE;
}
if (bounds.contains("y2")) {
enemy.y2 = bounds["y2"].get_value<int>() * TILE_SIZE;
}
}
// Color
if (enemy_node.contains("color")) {
enemy.color = enemy_node["color"].get_value_or<std::string>("white");
} else {
enemy.color = "white";
}
// Optional fields
if (enemy_node.contains("flip")) {
enemy.flip = enemy_node["flip"].get_value_or<bool>(false);
} else {
enemy.flip = false;
}
if (enemy_node.contains("mirror")) {
enemy.mirror = enemy_node["mirror"].get_value_or<bool>(false);
} else {
enemy.mirror = false;
}
if (enemy_node.contains("frame")) {
enemy.frame = enemy_node["frame"].get_value_or<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.contains("items") && !yaml["items"].is_null()) {
const auto& items_node = yaml["items"];
for (const auto& item_node : items_node) {
Item::Data item;
// Tileset file
if (item_node.contains("tileSetFile")) {
item.tile_set_file = item_node["tileSetFile"].get_value<std::string>();
}
// Tile index
if (item_node.contains("tile")) {
item.tile = item_node["tile"].get_value<int>();
}
// Position (in tiles, convert to pixels)
if (item_node.contains("position")) {
const auto& pos = item_node["position"];
if (pos.contains("x")) {
item.x = pos["x"].get_value<float>() * TILE_SIZE;
}
if (pos.contains("y")) {
item.y = pos["y"].get_value<float>() * TILE_SIZE;
}
}
// Counter
if (item_node.contains("counter")) {
item.counter = item_node["counter"].get_value_or<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";
}
}
// Delegación a funciones especializadas
parseRoomConfig(yaml, room, FILE_NAME);
parseTilemap(yaml, room, FILE_NAME, verbose);
parseEnemies(yaml, room, verbose);
parseItems(yaml, room, verbose);
if (verbose) {
std::cout << "Room loaded successfully: " << FILE_NAME << '\n';

View File

@@ -68,4 +68,66 @@ class RoomLoader {
* @return Vector 1D flat con 512 elementos
*/
static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>;
/**
* @brief Parsea la configuración general de la habitación
* @param yaml Nodo raíz del YAML
* @param room Estructura de datos de la habitación a rellenar
* @param file_name Nombre del archivo para logging
*/
static void parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name);
/**
* @brief Parsea las conexiones de la habitación (arriba/abajo/izq/der)
* @param conn_node Nodo YAML con las conexiones
* @param room Estructura de datos de la habitación a rellenar
*/
static void parseRoomConnections(const fkyaml::node& conn_node, Room::Data& room);
/**
* @brief Parsea el tilemap de la habitación
* @param yaml Nodo raíz del YAML
* @param room Estructura de datos de la habitación a rellenar
* @param file_name Nombre del archivo para logging
* @param verbose Si true, muestra información de debug
*/
static void parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose);
/**
* @brief Parsea la lista de enemigos de la habitación
* @param yaml Nodo raíz del YAML
* @param room Estructura de datos de la habitación a rellenar
* @param verbose Si true, muestra información de debug
*/
static void parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose);
/**
* @brief Parsea los datos de un enemigo individual
* @param enemy_node Nodo YAML del enemigo
* @return Estructura Enemy::Data con los datos parseados
*/
static auto parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data;
/**
* @brief Parsea los límites de movimiento de un enemigo
* @param bounds_node Nodo YAML con los límites
* @param enemy Estructura del enemigo a rellenar
*/
static void parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy);
/**
* @brief Parsea la lista de items de la habitación
* @param yaml Nodo raíz del YAML
* @param room Estructura de datos de la habitación a rellenar
* @param verbose Si true, muestra información de debug
*/
static void parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose);
/**
* @brief Parsea los datos de un item individual
* @param item_node Nodo YAML del item
* @param room Datos de la habitación (para colores por defecto)
* @return Estructura Item::Data con los datos parseados
*/
static auto parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data;
};

View File

@@ -248,9 +248,9 @@ void Ending2::iniSpriteList() {
sprite_list_.emplace_back("jailbattle_alien");
sprite_list_.emplace_back("jailbattle_human");
sprite_list_.emplace_back("jailer_#1");
sprite_list_.emplace_back("jailer_#2");
sprite_list_.emplace_back("jailer_#3");
sprite_list_.emplace_back("jailer1");
sprite_list_.emplace_back("jailer2");
sprite_list_.emplace_back("jailer3");
sprite_list_.emplace_back("bry");
sprite_list_.emplace_back("upv_student");