#pragma once #include #include #include #include #include "game/entities/event_bus.hpp" class Entity; class Sarcophagus; class Door; // Contenidor i coordinador d'entitats d'un nivell. Responsabilitats: // 1. `add` registra una entitat, la connecta al bus i manté propietat. // 2. `update(dt)` propaga el tick a totes. // 3. Comptador de sarcòfags oberts — quan iguala el total registrat, // crida `door_->open()` automàticament. // 4. `notifyPlayerEnteredTile(col, row)` — fan-out del hook per a tots // els sarcòfags (i qualsevol entitat futura que s'hi subscrigui via // `notifyTileEntered`). // // NO és un singleton: es crea una instància per nivell. De moment no // s'usa encara al GameScene (andamiatge pur). class EntityManager { public: EntityManager(); ~EntityManager(); EntityManager(const EntityManager&) = delete; EntityManager(EntityManager&&) = delete; auto operator=(const EntityManager&) -> EntityManager& = delete; auto operator=(EntityManager&&) -> EntityManager& = delete; // Registre d'una entitat. L'ownership és del manager; retorna // l'observador per conveniència (no eximeix que el manager la destrueixi). auto add(std::unique_ptr entity) -> Entity*; // Marca una entitat com a porta principal del nivell. N'hi ha només // una. Si ja n'hi ha una assignada, la substitueix (útil a tests). void setDoor(Door* door); // Marca una entitat com a sarcòfag — si no es passa per `add` amb // type=sarcophagus no es compta al total. Útil en combinació amb // `add` quan es fa addSarcophagus(unique_ptr). auto addSarcophagus(std::unique_ptr sarc) -> Sarcophagus*; // Tick de totes les entitats. void update(float delta_time); // Dibuix de totes les entitats. Sense ordenació per z: la crida dura // l'ordre d'inserció. El z-order fi (interleaving amb el Player per // feetY) queda per a una tasca posterior. void renderAll(); // Fan-out del hook de moviment de jugador: per a cada sarcòfag, // cridar notifyTileEntered. Les entitats no-sarcòfag ho ignoren per // defecte (veure Entity::notifyTileEntered). void notifyPlayerEnteredTile(int col, int row); // Carrega els spawns d'un YAML de nivell i els afegeix al manager: // 1. Llegeix el bloc `entities:` via EntityLoader. // 2. Per cada spawn: crea via factory, carrega la seva surface al // Resource::Cache, calcula pixel_rect_ segons el tipus // (sarc: Map::getSarcRect; altres: col/row del tilemap) i l'afegeix. // 3. Loguea `Entities: N loaded` per facilitar el smoke d'arrencada. // Requereix que Map::loadFrom ja s'hagi cridat (necessita // `Map::tile_size`, `tilemap_origin_*` i `getSarcRect`). void loadFromLevel(const std::string& level_yaml_path); [[nodiscard]] auto getBus() -> EventBus& { return bus_; } [[nodiscard]] auto entityCount() const -> std::size_t { return entities_.size(); } [[nodiscard]] auto sarcophagusCount() const -> std::size_t { return total_sarcs_; } [[nodiscard]] auto openedSarcophagusCount() const -> std::size_t { return opened_sarcs_; } private: EventBus bus_; std::vector> entities_; Door* door_{nullptr}; std::size_t total_sarcs_{0}; std::size_t opened_sarcs_{0}; EventBus::SubId sarc_sub_id_{0}; EventBus::SubId tile_sub_id_{0}; };