feat(game-scene): FSM mínima ROOM_INTRO/PLAYING/ROOM_OUTRO sense efectes

This commit is contained in:
JailDesigner committed 2026-04-26 08:51:56 +02:00
1 parent decf9f5d90
commit 651db50a93
2 files changed
+100 -4

No files matched your search

+65 -4
View File
@@ -263,11 +263,13 @@ GameScene::GameScene(Config config)
// Les surfaces de les entitats es carreguen al Resource::Cache aquí.
entity_manager_.loadFromLevel(config_.map_yaml);
// Subscripcions bàsiques al bus del nivell: de moment només logs, sense
// tocar ni la vida del jugador ni l'estat de la escena. Serà la base
// sobre la qual cablejar HUD i fi de nivell més endavant.
entity_manager_.getBus().subscribe("level_complete", [](const Event& ev) {
// Subscripcions bàsiques al bus del nivell. `level_complete` també
// dispara la transició a ROOM_OUTRO si encara estem a PLAYING; les
// re-emissions es filtren per estat per no re-entrar mai des d'una
// transició ja en marxa.
entity_manager_.getBus().subscribe("level_complete", [this](const Event& ev) {
std::cout << "[LEVEL COMPLETE] player_id=" << ev.player_id << '\n';
if (state_ == State::PLAYING) { setState(State::ROOM_OUTRO); }
});
entity_manager_.getBus().subscribe("player_hit", [](const Event& ev) {
const auto* dmg = std::get_if<int>(&ev.payload);
@@ -395,10 +397,64 @@ GameScene::GameScene(Config config)
auto pause_surface = Resource::Cache::get().getSurface(PAUSE_FONT_KEY);
pause_font_ = std::make_shared<Text>(pause_surface, UiConfig::get().placeholderFont().fnt);
pause_font_->setDefaultKerning(UiConfig::get().placeholderFont().kerning);
// Log d'estat inicial: la FSM arrenca a ROOM_INTRO. En aquesta fita
// les transicions són instantànies (sense fades ni text) i el primer
// tick d'`updateRoomTransition` ja saltarà a PLAYING.
std::cout << "[ROOM] state=ROOM_INTRO (initial)" << '\n';
}
GameScene::~GameScene() = default;
namespace {
// Nom textual d'un State per als logs de transició. L'enum és privat
// a GameScene, així que la funció ha de viure aquí com a lambda
// local del setState — la deixem com a constexpr que rep l'enum
// intern via auto-deducció a partir del seu valor entrant.
constexpr auto stateName(GameScene::State s) -> const char* {
using S = GameScene::State;
switch (s) {
case S::ROOM_INTRO:
return "ROOM_INTRO";
case S::PLAYING:
return "PLAYING";
case S::ROOM_OUTRO:
return "ROOM_OUTRO";
}
return "?";
}
} // namespace
void GameScene::setState(State new_state) {
if (new_state == state_) { return; }
std::cout << "[ROOM] " << stateName(state_) << " -> " << stateName(new_state) << '\n';
state_ = new_state;
// Els acumuladors de la transició de sala (sub-fase, elapsed) viuran
// aquí als commits següents. De moment no en tenim cap.
}
void GameScene::updateRoomTransition(int /*delta_ms*/) {
// Implementació mínima: no hi ha sub-fases ni fades encara, així que
// ROOM_INTRO i ROOM_OUTRO són efectivament instantanis. El bucle de
// sala queda demostrat (INTRO → PLAYING; al level_complete OUTRO →
// INTRO → PLAYING) sense efectes visuals. Els commits 3 i 4
// afegiran timings i sub-fases reals.
if (state_ == State::ROOM_INTRO) {
setState(State::PLAYING);
return;
}
if (state_ == State::ROOM_OUTRO) {
// Placeholder fins a l'itinerari de sales: tornem a la mateixa
// sala. No es reinicia res — porta + sarcòfags continuen a
// l'estat OPEN, com era l'acord.
// TODO(itinerari): seleccionar la pròxima sala (incrementar
// `room_index_`, intercanviar `config_.map_yaml`, recrear
// tilemap/entitats) abans de tornar a ROOM_INTRO.
setState(State::ROOM_INTRO);
return;
}
}
void GameScene::spawnDust(float feet_x_center, float feet_y, bool is_landing) {
// Mida del sprite de Dust llegida del seu YAML. Hardcoded per
// simplificar — si canvia, només cal tocar dust.yaml + aquesta
@@ -516,6 +572,11 @@ void GameScene::update(int delta_ms) {
handlePauseInput();
updatePauseTransition(delta_ms);
// Transició de sala: viu en temps real (no escalada per la pausa)
// perquè és UI. Avança avans del bloc de món perquè quan PLAYING
// arrenque ja sigui efectiu en el mateix frame.
updateRoomTransition(delta_ms);
#ifdef _DEBUG
// Toggle de l'editor: només si no hi ha cap transició de pausa ni
// pausa consolidada. L'editor mateix no consumeix la tecla — la