feat(intro): delay de spawn independent per al segon jugador en mode BOTH
This commit is contained in:
1 parent
99eb42b319
commit
8e2865efbd
5 files changed
+55
-29
No files matched your search
@@ -11,7 +11,8 @@ room_intro:
|
||||
text_hold_ms: 2000 # text quiet al centre
|
||||
text_exit_ms: 400 # text centre → fora per l'esquerra
|
||||
line_gap_px: -4 # px extra entre les dues línies (piràmide / sala)
|
||||
player_spawn_delay_ms: 2400 # ms des de l'inici d'INTRO al spawn aeri.
|
||||
player_spawn_delay_ms: 2400 # ms des de l'inici d'INTRO al spawn aeri.
|
||||
player2_spawn_delay_ms: 2700 # només mode BOTH. Trenca la simultaneïtat.
|
||||
|
||||
room_outro:
|
||||
text_enter_ms: 400
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,19 +99,21 @@ class GameScene : public Scene {
|
||||
std::array<bool, 2> players_starts_active_{false, false};
|
||||
|
||||
// Mil·lisegons des de l'entrada en ROOM_INTRO, per disparar la
|
||||
// cinemàtica de spawn aeri quan s'arriba a
|
||||
// `transition_config_.player_spawn_delay_ms`. Es reseteja a
|
||||
// `setState(ROOM_INTRO)`. `players_spawned_in_intro_` garanteix
|
||||
// que el trigger només es dispara una vegada per cicle.
|
||||
// cinemàtica de spawn aeri quan s'arriba al delay corresponent al
|
||||
// slot. Es reseteja a `setState(ROOM_INTRO)`. Cada slot té el seu
|
||||
// propi flag de "ja he caigut" — així podem caure en moments
|
||||
// distints en mode BOTH (`player_spawn_delay_ms` per a P1 i
|
||||
// `player2_spawn_delay_ms` per a P2).
|
||||
int room_intro_elapsed_ms_{0};
|
||||
bool players_spawned_in_intro_{false};
|
||||
std::array<bool, 2> players_spawned_in_intro_{false, false};
|
||||
|
||||
// Cinemàtica de spawn: posa els slots actius en AIRBORNE des d'una
|
||||
// altura fora de pantalla. Cridat per `updateRoomTransition` quan
|
||||
// `room_intro_elapsed_ms_` supera el delay configurat. Idempotent
|
||||
// (consulta `players_spawned_in_intro_`). També és el punt al qual
|
||||
// es connectarà el respawn post-mort en el futur.
|
||||
void triggerActivePlayerSpawn();
|
||||
// Cinemàtica de spawn d'un slot concret. Posa el slot indicat en
|
||||
// AIRBORNE des d'una altura fora de pantalla. Cridat per
|
||||
// `updateRoomTransition` quan `room_intro_elapsed_ms_` supera el
|
||||
// delay específic de l'slot. Idempotent (consulta el flag corresponent
|
||||
// a `players_spawned_in_intro_`). També és el punt al qual es
|
||||
// connectarà el respawn post-mort en el futur.
|
||||
void triggerPlayerSpawn(std::size_t slot_index);
|
||||
|
||||
// Vista plana de punters crus — la fa servir Player com a llista
|
||||
// d'obstacles mòbils a la callback de col·lisió. Es construeix un sol
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace RoomFsm {
|
||||
cfg.intro_text_hold_ms = readChildInt(n, "text_hold_ms", cfg.intro_text_hold_ms);
|
||||
cfg.intro_text_exit_ms = readChildInt(n, "text_exit_ms", cfg.intro_text_exit_ms);
|
||||
cfg.player_spawn_delay_ms = readChildInt(n, "player_spawn_delay_ms", cfg.player_spawn_delay_ms);
|
||||
// Per defecte el segon jugador cau alhora que el primer.
|
||||
// El YAML pot trencar la simultaneïtat fixant un valor propi.
|
||||
cfg.player2_spawn_delay_ms = readChildInt(n, "player2_spawn_delay_ms", cfg.player_spawn_delay_ms);
|
||||
cfg.intro_text_line_gap_px = readChildInt(n, "line_gap_px", cfg.intro_text_line_gap_px);
|
||||
}
|
||||
if (yaml.contains("room_outro")) {
|
||||
|
||||
@@ -57,6 +57,14 @@ namespace RoomFsm {
|
||||
// si el YAML no defineix res — només pensat com a degradació.
|
||||
int player_spawn_delay_ms{500};
|
||||
|
||||
// Delay independent per al segon jugador, **només quan els dos
|
||||
// slots estan actius** (mode BOTH). En single-player (P1 o P2
|
||||
// sols) s'usa sempre `player_spawn_delay_ms` per al jugador
|
||||
// actiu. Si el YAML no fixa aquest valor, el `loadConfig` el
|
||||
// copia de `player_spawn_delay_ms` perquè els dos players caiguin
|
||||
// alhora — comportament històric del joc.
|
||||
int player2_spawn_delay_ms{500};
|
||||
|
||||
// Píxels extra entre les dues línies del text d'INTRO (piràmide
|
||||
// damunt, sala davall). Es sumen al `lineHeight` natural del
|
||||
// font per separar visualment les dues línies. 0 = stack
|
||||
|
||||
Reference in new issue
Block a user