feat(entity-manager): comptador player_exited agrega a level_complete
This commit is contained in:
1 parent
5c5cd1d5da
commit
28e55a0615
3 files changed
+47
No files matched your search
@@ -32,11 +32,37 @@ EntityManager::EntityManager() {
|
|||||||
const auto* tile = std::get_if<TilePos>(&ev.payload);
|
const auto* tile = std::get_if<TilePos>(&ev.payload);
|
||||||
if (tile != nullptr) { notifyPlayerTilePainted(tile->col, tile->row); }
|
if (tile != nullptr) { notifyPlayerTilePainted(tile->col, tile->row); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Subscripció a `player_exited` (publicat per Door en travessar la
|
||||||
|
// porta oberta amb un jugador): comptem una vegada per jugador i,
|
||||||
|
// quan tots els jugadors actius han eixit, emetem `level_complete`
|
||||||
|
// — l'event d'agregat que GameScene escolta per disparar la
|
||||||
|
// transició FSM a ROOM_OUTRO. La idempotència de Door (check
|
||||||
|
// `isExited`) garanteix que cada jugador suma com a màxim un cop.
|
||||||
|
exit_sub_id_ = bus_.subscribe("player_exited", [this](const Event& /*ev*/) {
|
||||||
|
++exited_players_;
|
||||||
|
if (level_complete_emitted_) { return; }
|
||||||
|
if (expected_players_ > 0 && exited_players_ >= expected_players_) {
|
||||||
|
level_complete_emitted_ = true;
|
||||||
|
bus_.publish(Event{
|
||||||
|
.name = "level_complete",
|
||||||
|
.payload = std::monostate{},
|
||||||
|
.player_id = -1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager::~EntityManager() {
|
EntityManager::~EntityManager() {
|
||||||
bus_.unsubscribe(sarc_sub_id_);
|
bus_.unsubscribe(sarc_sub_id_);
|
||||||
bus_.unsubscribe(tile_sub_id_);
|
bus_.unsubscribe(tile_sub_id_);
|
||||||
|
bus_.unsubscribe(exit_sub_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityManager::setExpectedPlayerCount(int n) {
|
||||||
|
expected_players_ = n;
|
||||||
|
exited_players_ = 0;
|
||||||
|
level_complete_emitted_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EntityManager::add(std::unique_ptr<Entity> entity) -> Entity* {
|
auto EntityManager::add(std::unique_ptr<Entity> entity) -> Entity* {
|
||||||
|
|||||||
@@ -90,10 +90,17 @@ class EntityManager {
|
|||||||
// `Map::tile_size`, `tilemap_origin_*` i `getSarcRect`).
|
// `Map::tile_size`, `tilemap_origin_*` i `getSarcRect`).
|
||||||
void loadFromLevel(const std::string& level_yaml_path);
|
void loadFromLevel(const std::string& level_yaml_path);
|
||||||
|
|
||||||
|
// Fixa quants jugadors actius es consideren al recompte d'EXITED.
|
||||||
|
// Cridat per GameScene un cop instanciats els jugadors. Si manca,
|
||||||
|
// `expected_players_ = 0` i mai s'emet `level_complete` automàticament.
|
||||||
|
// Cridar-lo de nou al respawn (futur reload) reseteja el comptador.
|
||||||
|
void setExpectedPlayerCount(int n);
|
||||||
|
|
||||||
[[nodiscard]] auto getBus() -> EventBus& { return bus_; }
|
[[nodiscard]] auto getBus() -> EventBus& { return bus_; }
|
||||||
[[nodiscard]] auto entityCount() const -> std::size_t { return entities_.size(); }
|
[[nodiscard]] auto entityCount() const -> std::size_t { return entities_.size(); }
|
||||||
[[nodiscard]] auto sarcophagusCount() const -> std::size_t { return total_sarcs_; }
|
[[nodiscard]] auto sarcophagusCount() const -> std::size_t { return total_sarcs_; }
|
||||||
[[nodiscard]] auto openedSarcophagusCount() const -> std::size_t { return opened_sarcs_; }
|
[[nodiscard]] auto openedSarcophagusCount() const -> std::size_t { return opened_sarcs_; }
|
||||||
|
[[nodiscard]] auto exitedPlayerCount() const -> std::size_t { return exited_players_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventBus bus_;
|
EventBus bus_;
|
||||||
@@ -101,6 +108,14 @@ class EntityManager {
|
|||||||
Door* door_{nullptr};
|
Door* door_{nullptr};
|
||||||
std::size_t total_sarcs_{0};
|
std::size_t total_sarcs_{0};
|
||||||
std::size_t opened_sarcs_{0};
|
std::size_t opened_sarcs_{0};
|
||||||
|
// Recompte d'`player_exited`: incrementat a la subscripció al bus,
|
||||||
|
// resetejat per `setExpectedPlayerCount`. Quan `exited_players_` arriba
|
||||||
|
// a `expected_players_` (i tots dos > 0), publica `level_complete`
|
||||||
|
// amb `player_id = -1` (event d'agregat, no atribuible a un jugador).
|
||||||
|
int expected_players_{0};
|
||||||
|
int exited_players_{0};
|
||||||
|
bool level_complete_emitted_{false};
|
||||||
EventBus::SubId sarc_sub_id_{0};
|
EventBus::SubId sarc_sub_id_{0};
|
||||||
EventBus::SubId tile_sub_id_{0};
|
EventBus::SubId tile_sub_id_{0};
|
||||||
|
EventBus::SubId exit_sub_id_{0};
|
||||||
};
|
};
|
||||||
@@ -367,6 +367,12 @@ GameScene::GameScene(Config config)
|
|||||||
players_view_.reserve(players_.size());
|
players_view_.reserve(players_.size());
|
||||||
std::ranges::transform(players_, std::back_inserter(players_view_), [](const auto& p) { return p.get(); });
|
std::ranges::transform(players_, std::back_inserter(players_view_), [](const auto& p) { return p.get(); });
|
||||||
for (auto& p : players_) { p->setOtherPlayers(&players_view_); }
|
for (auto& p : players_) { p->setOtherPlayers(&players_view_); }
|
||||||
|
|
||||||
|
// Comptador d'EXITED a EntityManager: publica `level_complete` quan
|
||||||
|
// tots els jugadors actius han travessat la porta. Cap setExpectedPlayerCount
|
||||||
|
// ha d'inicialitzar-se abans del primer `player_exited`; ho fem aquí
|
||||||
|
// perquè ja sabem el nombre real d'instàncies.
|
||||||
|
entity_manager_.setExpectedPlayerCount(static_cast<int>(players_.size()));
|
||||||
// El snap també empeny lateralment si l'altre jugador ocupa el carril:
|
// El snap també empeny lateralment si l'altre jugador ocupa el carril:
|
||||||
// passem el mateix factor perquè vaja al mateix ritme que el resolver.
|
// passem el mateix factor perquè vaja al mateix ritme que el resolver.
|
||||||
for (auto& p : players_) { p->setPushFactor(push_factor_); }
|
for (auto& p : players_) { p->setPushFactor(push_factor_); }
|
||||||
|
|||||||
Reference in new issue
Block a user