feat(intro): delay de spawn independent per al segon jugador en mode BOTH

This commit is contained in:
JailDesigner committed 2026-04-26 18:55:30 +02:00
1 parent 99eb42b319
commit 8e2865efbd
5 files changed
+55 -29

No files matched your search

+29 -17
View File
@@ -363,9 +363,10 @@ GameScene::GameScene(Config config)
players_.emplace_back(std::make_unique<Player>(ANIM_P2, ID_P2, p2_x, SPAWN.y, CONTROLS_P2, Map::makeInfo(), P2_PAINT));
// Tots els slots arrenquen DISABLED. Els actius els reactivarà
// `updateRoomTransition` quan s'esgote `player_spawn_delay_ms_` dins
// de ROOM_INTRO (cinemàtica de caiguda); els inactius es queden
// DISABLED tot el cicle de sala.
// `updateRoomTransition` quan s'esgote el delay corresponent dins
// de ROOM_INTRO (`player_spawn_delay_ms` per al primer, i
// `player2_spawn_delay_ms` per al segon en mode BOTH). Els inactius
// es queden DISABLED tot el cicle de sala.
for (auto& p : players_) { p->disable(); }
// PaintLayer: font única del pintat del nivell. Es crea després de
@@ -535,12 +536,13 @@ void GameScene::enterRoomIntro() {
state_ = RoomFsm::State::ROOM_INTRO;
transition_ = {};
room_intro_elapsed_ms_ = 0;
players_spawned_in_intro_ = false;
players_spawned_in_intro_.fill(false);
}
void GameScene::triggerActivePlayerSpawn() {
if (players_spawned_in_intro_) { return; }
players_spawned_in_intro_ = true;
void GameScene::triggerPlayerSpawn(std::size_t slot_index) {
if (slot_index >= players_spawned_in_intro_.size()) { return; }
if (players_spawned_in_intro_[slot_index]) { return; }
players_spawned_in_intro_[slot_index] = true;
// Recalcula spawn per si door_col canvia entre sales (avui no, però
// la lògica ja queda preparada per a l'itinerari).
@@ -551,14 +553,11 @@ void GameScene::triggerActivePlayerSpawn() {
// amb un sol actiu, el reposicionem al centre exacte.
const float SINGLE_X = SPAWN.p1_x + static_cast<float>(Map::tile_size);
for (std::size_t i = 0; i < players_.size(); ++i) {
if (!players_starts_active_[i]) { continue; }
float x = SINGLE_X;
if (BOTH_ACTIVE) { x = (i == 0) ? SPAWN.p1_x : SPAWN.p2_x; }
players_[i]->spawnFromAir(x, SPAWN.y);
}
float x = SINGLE_X;
if (BOTH_ACTIVE) { x = (slot_index == 0) ? SPAWN.p1_x : SPAWN.p2_x; }
players_[slot_index]->spawnFromAir(x, SPAWN.y);
std::cout << "[ROOM] spawn cinematic: airborne entry for active players\n";
std::cout << "[ROOM] spawn cinematic P" << (slot_index + 1) << ": airborne entry\n";
}
void GameScene::setState(RoomFsm::State new_state) {
@@ -570,7 +569,7 @@ void GameScene::setState(RoomFsm::State new_state) {
// l'spawn aeri perquè es torne a disparar al delay configurat.
if (new_state == RoomFsm::State::ROOM_INTRO) {
room_intro_elapsed_ms_ = 0;
players_spawned_in_intro_ = false;
players_spawned_in_intro_.fill(false);
}
// L'avanç de sala (OUTRO → INTRO) NO viu ací: el dispara
// `updateRoomTransition` quan la FSM detecta el final de l'OUTRO,
@@ -587,8 +586,21 @@ void GameScene::updateRoomTransition(int delta_ms) {
// respawn post-mort sense que la FSM de sala hi haja d'intervenir.
if (state_ == RoomFsm::State::ROOM_INTRO) {
room_intro_elapsed_ms_ += delta_ms;
if (!players_spawned_in_intro_ && room_intro_elapsed_ms_ >= transition_config_.player_spawn_delay_ms) {
triggerActivePlayerSpawn();
// Cada slot actiu pot caure en un moment distint quan els dos
// estan actius (mode BOTH): P1 amb player_spawn_delay_ms i P2
// amb player2_spawn_delay_ms. En single-player (P1 o P2 sols)
// l'slot actiu fa servir player_spawn_delay_ms — el segon valor
// queda inactiu, com ha demanat el disseny.
const bool BOTH_ACTIVE = players_starts_active_[0] && players_starts_active_[1];
for (std::size_t i = 0; i < players_starts_active_.size(); ++i) {
if (!players_starts_active_[i]) { continue; }
if (players_spawned_in_intro_[i]) { continue; }
const int DELAY = (i == 1 && BOTH_ACTIVE)
? transition_config_.player2_spawn_delay_ms
: transition_config_.player_spawn_delay_ms;
if (room_intro_elapsed_ms_ >= DELAY) {
triggerPlayerSpawn(i);
}
}
}