#include "door_manager.hpp" #include // Para std::move #include "game/entities/door.hpp" // Para Door #include "game/gameplay/collision_map.hpp" // Para CollisionMap #include "game/gameplay/door_tracker.hpp" // Para DoorTracker #include "game/gameplay/inventory.hpp" // Para Inventory #include "game/gameplay/tile_collider.hpp" // Para TileCollider::Tile #include "utils/defines.hpp" // Para Map::WIDTH, Tile::SIZE #include "utils/utils.hpp" // Para checkCollision // Constructor DoorManager::DoorManager(std::string room_id, CollisionMap* collision_map) : room_id_(std::move(room_id)), collision_map_(collision_map) { } // Añade una puerta. Si está bloqueante (CLOSED), pinta sus 4 tiles como WALL // en el CollisionMap. Si ya está OPENED (porque venía persistida del // DoorTracker), no se tocan los tiles. void DoorManager::addDoor(std::shared_ptr door) { // NOLINT(readability-identifier-naming) if (door->isBlocking()) { writeDoorTiles(*door, static_cast(TileCollider::Tile::WALL)); } doors_.push_back(std::move(door)); } // Elimina todas las puertas void DoorManager::clear() { doors_.clear(); } // Actualiza animaciones y procesa transiciones a OPENED void DoorManager::update(float delta_time) { for (const auto& door : doors_) { door->update(delta_time); // Si la puerta acaba de transicionar a OPENED, liberar los tiles y persistir if (door->justOpened()) { writeDoorTiles(*door, static_cast(TileCollider::Tile::EMPTY)); DoorTracker::get()->addDoor(room_id_, door->getPos()); } } } // Renderiza todas las puertas void DoorManager::render() { for (const auto& door : doors_) { door->render(); } } // Pausa/despausa todas las puertas void DoorManager::setPaused(bool paused) { for (const auto& door : doors_) { door->setPaused(paused); } } // Intenta abrir las puertas cercanas al jugador void DoorManager::tryUnlock(const SDL_FRect& player_rect) { // Infla el rect del jugador 1 px en cada lado para detectar contacto const SDL_FRect INFLATED = { .x = player_rect.x - 1.0F, .y = player_rect.y - 1.0F, .w = player_rect.w + 2.0F, .h = player_rect.h + 2.0F, }; for (const auto& door : doors_) { if (door->getState() != Door::State::CLOSED) { continue; } if (::checkCollision(INFLATED, door->getCollider()) && Inventory::get()->hasKey(door->getId())) { door->startOpening(); } } } #ifdef _DEBUG // Mueve una puerta del editor: limpia los WALLs viejos, reposiciona el sprite, // y reescribe los WALLs nuevos si la puerta sigue siendo bloqueante. void DoorManager::moveDoor(int index, float x, float y) { if (index < 0 || index >= static_cast(doors_.size())) { return; } auto& door = doors_[index]; // Limpiar los WALLs viejos antes de mover if (door->isBlocking()) { writeDoorTiles(*door, static_cast(TileCollider::Tile::EMPTY)); } // Reposicionar el sprite y el collider del Door door->setPosition(x, y); // Re-escribir los WALLs nuevos en la nueva posición si sigue siendo bloqueante if (door->isBlocking()) { writeDoorTiles(*door, static_cast(TileCollider::Tile::WALL)); } } // Elimina una puerta del editor, limpiando los WALLs antes de borrarla del vector void DoorManager::removeDoor(int index) { if (index < 0 || index >= static_cast(doors_.size())) { return; } auto& door = doors_[index]; if (door->isBlocking()) { writeDoorTiles(*door, static_cast(TileCollider::Tile::EMPTY)); } doors_.erase(doors_.begin() + index); } #endif // Setea las 4 celdas que ocupa la puerta (1 col × 4 filas) al valor indicado void DoorManager::writeDoorTiles(const Door& door, int tile_value) { // Convertir posición en píxeles a coordenadas de tile const SDL_FPoint POS = door.getPos(); const int COL = static_cast(POS.x) / Tile::SIZE; const int ROW = static_cast(POS.y) / Tile::SIZE; for (int i = 0; i < DOOR_TILES_HEIGHT; ++i) { const int INDEX = ((ROW + i) * Map::WIDTH) + COL; collision_map_->setCollisionTile(INDEX, tile_value); } }