feat(level-manager): salts debug entre sales (només Debug)
Tecles [ i ] al keys.yaml (prev_room / next_room) que mouen LevelManager::setIndex en ±1 i recarreguen la sala via loadRoom + enterRoomIntro. Ignorades si la pausa està activa o l'editor obert (qualsevol dels dos invalida l'estat editat). Refactor de la FSM al mateix pas: l'avanç de sala (LevelManager + loadRoom) ja no viu dins setState — el dispara updateRoomTransition quan detecta el final de l'OUTRO via advanceToNextRoom. setState torna a ser una transició pura, condició necessària perquè el salt debug puga entrar a INTRO sense disparar un advance addicional. Nou helper enterRoomIntro() reusable per la sortida de l'OUTRO i pels salts; idempotent quan ja s'estava a INTRO.
This commit is contained in:
1 parent
d52cc1c509
commit
b147590a39
3 files changed
+78
-15
No files matched your search
@@ -500,6 +500,21 @@ void GameScene::advanceToNextRoom() {
|
||||
}
|
||||
room_index_ = mgr.currentRoom();
|
||||
loadRoom(mgr.currentPath());
|
||||
enterRoomIntro();
|
||||
}
|
||||
|
||||
void GameScene::enterRoomIntro() {
|
||||
// Anotem la transició al log si veníem d'un altre estat; si ja
|
||||
// estàvem a INTRO (cas típic d'un salt debug) també queda ben clar.
|
||||
if (state_ != RoomFsm::State::ROOM_INTRO) {
|
||||
std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> ROOM_INTRO\n";
|
||||
} else {
|
||||
std::cout << "[ROOM] ROOM_INTRO restart (cinemàtica reiniciada)\n";
|
||||
}
|
||||
state_ = RoomFsm::State::ROOM_INTRO;
|
||||
transition_ = {};
|
||||
room_intro_elapsed_ms_ = 0;
|
||||
players_spawned_in_intro_ = false;
|
||||
}
|
||||
|
||||
void GameScene::triggerActivePlayerSpawn() {
|
||||
@@ -528,7 +543,6 @@ void GameScene::triggerActivePlayerSpawn() {
|
||||
void GameScene::setState(RoomFsm::State new_state) {
|
||||
if (new_state == state_) { return; }
|
||||
std::cout << "[ROOM] " << RoomFsm::stateName(state_) << " -> " << RoomFsm::stateName(new_state) << '\n';
|
||||
const auto PREV = state_;
|
||||
state_ = new_state;
|
||||
transition_ = {};
|
||||
// En entrar a un nou cicle d'INTRO, resetegem el timer i el flag de
|
||||
@@ -537,15 +551,12 @@ void GameScene::setState(RoomFsm::State new_state) {
|
||||
room_intro_elapsed_ms_ = 0;
|
||||
players_spawned_in_intro_ = false;
|
||||
}
|
||||
// En tornar a ROOM_INTRO des de ROOM_OUTRO ja hi ha itinerari: el
|
||||
// jugador acaba de creuar la porta, així que avancem al següent
|
||||
// nivell del LevelManager i carreguem la nova sala. Si era l'última,
|
||||
// `advanceToNextRoom` fa loop a la primera. Per a la transició
|
||||
// inicial (PREV també és ROOM_INTRO, impossible amb el guard de dalt)
|
||||
// o vinguda d'un altre estat, no fem res.
|
||||
if (new_state == RoomFsm::State::ROOM_INTRO && PREV == RoomFsm::State::ROOM_OUTRO) {
|
||||
advanceToNextRoom();
|
||||
}
|
||||
// L'avanç de sala (OUTRO → INTRO) NO viu ací: el dispara
|
||||
// `updateRoomTransition` quan la FSM detecta el final de l'OUTRO,
|
||||
// cridant directament `advanceToNextRoom`. Això manté `setState`
|
||||
// com una transició pura, sense efectes col·laterals que
|
||||
// recarreguen sales — necessari per als salts debug que també
|
||||
// entren a INTRO sense passar per OUTRO.
|
||||
}
|
||||
|
||||
void GameScene::updateRoomTransition(int delta_ms) {
|
||||
@@ -561,7 +572,18 @@ void GameScene::updateRoomTransition(int delta_ms) {
|
||||
}
|
||||
|
||||
const auto NEXT = RoomFsm::advance(state_, transition_, transition_config_, delta_ms);
|
||||
if (NEXT != state_) { setState(NEXT); }
|
||||
if (NEXT != state_) {
|
||||
// El final de l'OUTRO no es resol amb un setState normal: cal
|
||||
// demanar al LevelManager el següent nivell i carregar-lo abans
|
||||
// d'entrar a INTRO. `advanceToNextRoom` fa tot el bloc i acaba
|
||||
// amb la FSM a ROOM_INTRO (via `enterRoomIntro`), així que no
|
||||
// fa falta el setState d'aquesta branca.
|
||||
if (NEXT == RoomFsm::State::ROOM_INTRO && state_ == RoomFsm::State::ROOM_OUTRO) {
|
||||
advanceToNextRoom();
|
||||
} else {
|
||||
setState(NEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::renderRoomFade() {
|
||||
@@ -769,6 +791,20 @@ namespace {
|
||||
return ev.type == SDL_EVENT_KEY_DOWN && ev.key.scancode == SC;
|
||||
});
|
||||
}
|
||||
|
||||
// Retorna -1 si s'ha premut prev_room, +1 si next_room, 0 si cap.
|
||||
// Si tots dos arriben en el mateix frame (poc probable amb teclat),
|
||||
// prev té prioritat — l'usuari sempre pot tornar a prémer next.
|
||||
auto detectRoomJump() -> int {
|
||||
const SDL_Scancode PREV_SC = KeyConfig::get().scancode("prev_room");
|
||||
const SDL_Scancode NEXT_SC = KeyConfig::get().scancode("next_room");
|
||||
for (const auto& ev : EventBuffer::events) {
|
||||
if (ev.type != SDL_EVENT_KEY_DOWN) { continue; }
|
||||
if (PREV_SC != SDL_SCANCODE_UNKNOWN && ev.key.scancode == PREV_SC) { return -1; }
|
||||
if (NEXT_SC != SDL_SCANCODE_UNKNOWN && ev.key.scancode == NEXT_SC) { return +1; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
@@ -788,6 +824,20 @@ void GameScene::update(int delta_ms) {
|
||||
if (pause_.state == PauseState::IDLE && detectEditorToggle()) {
|
||||
editor_.toggle(tilemap_);
|
||||
}
|
||||
|
||||
// Salts debug entre sales (`[` / `]`). Mútuament excloents amb la
|
||||
// pausa i amb l'editor: si qualsevol està actiu, ignorem la tecla
|
||||
// perquè el salt recarrega entitats i invalidaria l'estat editat.
|
||||
if (pause_.state == PauseState::IDLE && !editor_.active()) {
|
||||
const int DELTA = detectRoomJump();
|
||||
if (DELTA != 0) {
|
||||
auto& mgr = Levels::LevelManager::get();
|
||||
mgr.setIndex(mgr.index() + DELTA);
|
||||
room_index_ = mgr.currentRoom();
|
||||
loadRoom(mgr.currentPath());
|
||||
enterRoomIntro();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GlobalInputs::update(delta_ms);
|
||||
|
||||
Reference in new issue
Block a user