92 lines
3.8 KiB
C++
92 lines
3.8 KiB
C++
#pragma once
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <vector>
|
|
|
|
class SolidActor;
|
|
|
|
/**
|
|
* @brief Gestor de actores sólidos dinámicos (AABB) de una habitación.
|
|
*
|
|
* Paralelo al TileCollider: proporciona sweeps axis-aligned del Player
|
|
* contra una lista de AABBs de entidades (puertas, plataformas móviles,
|
|
* bloques empujables, ascensores, etc). El manager NO es propietario de
|
|
* los actores — sus entidades concretas viven en sus respectivos managers
|
|
* (DoorManager, PlatformManager, ...). Este manager solo mantiene una
|
|
* lista de raw pointers para consultas de colisión.
|
|
*
|
|
* Cross-room: igual que CollisionMap::updateBorders, este manager acepta
|
|
* punteros a los managers de las rooms adyacentes (setAdjacent). Cuando
|
|
* el Player está cerca del borde, los sweeps iteran también sobre los
|
|
* actores vecinos, trasladando sus AABBs por ±PlayArea::WIDTH/HEIGHT
|
|
* para ponerlos en el sistema de coordenadas de la room actual.
|
|
*/
|
|
class SolidActorManager {
|
|
public:
|
|
struct FloorHit {
|
|
float y{-1};
|
|
SolidActor* carrier{nullptr};
|
|
};
|
|
|
|
struct AdjacentActors {
|
|
SolidActorManager* upper{nullptr};
|
|
SolidActorManager* lower{nullptr};
|
|
SolidActorManager* left{nullptr};
|
|
SolidActorManager* right{nullptr};
|
|
};
|
|
|
|
SolidActorManager() = default;
|
|
~SolidActorManager() = default;
|
|
|
|
SolidActorManager(const SolidActorManager&) = delete;
|
|
auto operator=(const SolidActorManager&) -> SolidActorManager& = delete;
|
|
SolidActorManager(SolidActorManager&&) = delete;
|
|
auto operator=(SolidActorManager&&) -> SolidActorManager& = delete;
|
|
|
|
// Registro de actores (el manager no es propietario)
|
|
void registerActor(SolidActor* actor);
|
|
void unregisterActor(SolidActor* actor);
|
|
void clear();
|
|
|
|
// Cross-room: punteros a los managers de las rooms adyacentes
|
|
void setAdjacent(const AdjacentActors& adjacent);
|
|
void clearAdjacent();
|
|
|
|
// Sweeps del Player (paralelos a TileCollider). Todas las coordenadas
|
|
// están en el sistema de la room actual (room-local pixel space).
|
|
|
|
/// Devuelve el x del borde derecho del primer actor bloqueante cuyo AABB
|
|
/// esté "a la izquierda" del Player y solape su rect (px, py, pw, ph).
|
|
/// Collision::NONE si no hay colisión.
|
|
[[nodiscard]] auto checkWallLeft(float px, float py, float pw, float ph) const -> float;
|
|
|
|
/// Devuelve el x del borde izquierdo del primer actor bloqueante cuyo AABB
|
|
/// esté "a la derecha" del Player y solape su rect. Collision::NONE si no.
|
|
[[nodiscard]] auto checkWallRight(float px, float py, float pw, float ph) const -> float;
|
|
|
|
/// Devuelve el y del borde inferior del primer techo bloqueante que solape
|
|
/// la parte superior del Player a (px, py, pw). Collision::NONE si no.
|
|
[[nodiscard]] auto checkCeiling(float px, float py, float pw) const -> float;
|
|
|
|
/// Devuelve el suelo más cercano debajo de los pies del Player dentro del
|
|
/// rango vertical [foot_y_cur, foot_y_new]. Los actores ONEWAY_TOP solo
|
|
/// colisionan si foot_y_cur <= r.y (el Player venía desde arriba).
|
|
/// Si el actor tiene CARRY_ON_TOP, FloorHit.carrier apunta a él.
|
|
[[nodiscard]] auto checkFloor(float px, float foot_y_cur, float pw, float foot_y_new) const -> FloorHit;
|
|
|
|
/// Devuelve true si hay algún actor con top justo debajo de los pies
|
|
/// (dentro de 1 px). Usado por checkFalling para no desengancharse de
|
|
/// plataformas móviles.
|
|
[[nodiscard]] auto hasGroundBelow(float px, float foot_y, float pw) const -> bool;
|
|
|
|
private:
|
|
// Itera sobre todos los actores relevantes (locales + vecinos) aplicando
|
|
// el offset correcto a los AABBs vecinos. La lambda recibe (actor, aabb_world).
|
|
template <typename Fn>
|
|
void forEachActor(Fn&& fn) const;
|
|
|
|
std::vector<SolidActor*> actors_;
|
|
AdjacentActors adjacent_{};
|
|
};
|