127 lines
4.2 KiB
C++
127 lines
4.2 KiB
C++
#include "door_manager.hpp"
|
||
|
||
#include <utility> // 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> door) { // NOLINT(readability-identifier-naming)
|
||
if (door->isBlocking()) {
|
||
writeDoorTiles(*door, static_cast<int>(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<int>(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<int>(doors_.size())) { return; }
|
||
auto& door = doors_[index];
|
||
|
||
// Limpiar los WALLs viejos antes de mover
|
||
if (door->isBlocking()) {
|
||
writeDoorTiles(*door, static_cast<int>(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<int>(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<int>(doors_.size())) { return; }
|
||
auto& door = doors_[index];
|
||
|
||
if (door->isBlocking()) {
|
||
writeDoorTiles(*door, static_cast<int>(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<int>(POS.x) / Tile::SIZE;
|
||
const int ROW = static_cast<int>(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);
|
||
}
|
||
}
|