eliminats tots els SDL_Delay i bucles bloquejants (milestone 1)

- shakeScreen() convertit a màquina d'estats amb SDL_GetTicks (50ms per pas)
- killPlayer() convertit a seqüència de fases (Shaking → Waiting → Done)
- Fade FADE_FULLSCREEN convertit a per-frame amb alpha incremental
- Fade FADE_RANDOM_SQUARE convertit a per-frame (un quadrat cada 100ms)
- Title SUBSECTION_TITLE_2 convertit a no-bloquejant, variables static eliminades
- Corregit so duplicat del crashSound al títol
- Congelat input del jugador durant la seqüència de mort

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 19:02:44 +02:00
parent 4bd07216f3
commit 9365f80e8b
6 changed files with 204 additions and 119 deletions

View File

@@ -284,6 +284,12 @@ void Game::init() {
effect.flash = false;
effect.shake = false;
effect.shakeCounter = SHAKE_COUNTER;
deathShake.active = false;
deathShake.step = 0;
deathShake.lastStepTicks = 0;
deathSequence.phase = DeathPhase::None;
deathSequence.phaseStartTicks = 0;
deathSequence.player = nullptr;
helper.needCoffee = false;
helper.needCoffeeMachine = false;
helper.needPowerBall = false;
@@ -2363,23 +2369,50 @@ void Game::killPlayer(Player *player) {
player->removeExtraHit();
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
JA_PlaySound(coffeeOutSound);
} else {
} else if (deathSequence.phase == DeathPhase::None) {
JA_PauseMusic();
stopAllBalloons(10);
JA_PlaySound(playerCollisionSound);
shakeScreen();
SDL_Delay(500);
JA_PlaySound(coffeeOutSound);
player->setAlive(false);
if (allPlayersAreDead()) {
JA_StopMusic();
} else {
JA_ResumeMusic();
}
deathSequence.phase = DeathPhase::Shaking;
deathSequence.phaseStartTicks = SDL_GetTicks();
deathSequence.player = player;
}
}
}
// Actualiza la secuencia de muerte del jugador
void Game::updateDeathSequence() {
switch (deathSequence.phase) {
case DeathPhase::None:
case DeathPhase::Done:
break;
case DeathPhase::Shaking:
// Espera a que termine el efecto de agitación
if (!isDeathShaking()) {
deathSequence.phase = DeathPhase::Waiting;
deathSequence.phaseStartTicks = SDL_GetTicks();
}
break;
case DeathPhase::Waiting:
// Espera 500ms antes de completar la muerte
if (SDL_GetTicks() - deathSequence.phaseStartTicks >= 500) {
JA_PlaySound(coffeeOutSound);
deathSequence.player->setAlive(false);
if (allPlayersAreDead()) {
JA_StopMusic();
} else {
JA_ResumeMusic();
}
deathSequence.phase = DeathPhase::Done;
deathSequence.player = nullptr;
}
break;
}
}
// Calcula y establece el valor de amenaza en funcion de los globos activos
void Game::evaluateAndSetMenace() {
menaceCurrent = 0;
@@ -2439,6 +2472,15 @@ void Game::update() {
// Actualiza el audio
JA_Update();
// Actualiza los efectos basados en tiempo real (no en el throttle del juego)
updateDeathShake();
updateDeathSequence();
// Durante la secuencia de muerte, congela el resto del juego
if (deathSequence.phase == DeathPhase::Shaking || deathSequence.phase == DeathPhase::Waiting) {
return;
}
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
if (SDL_GetTicks() - ticks > ticksSpeed) {
// Actualiza el contador de ticks
@@ -2550,7 +2592,10 @@ void Game::updateBackground() {
grassSprite->setSpriteClip(0, (6 * (counter / 20 % 2)), 256, 6);
// Mueve los edificios en funcion de si está activo el efecto de agitarlos
if (effect.shake) {
if (deathShake.active) {
const int v[] = {-1, 1, -1, 1, -1, 1, -1, 0};
buildingsSprite->setPosX(v[deathShake.step]);
} else if (effect.shake) {
buildingsSprite->setPosX(((effect.shakeCounter % 2) * 2) - 1);
} else {
buildingsSprite->setPosX(0);
@@ -2868,44 +2913,32 @@ void Game::disableTimeStopItem() {
}
}
// Agita la pantalla
// Inicia el efecto de agitación intensa de la pantalla
void Game::shakeScreen() {
const int v[] = {-1, 1, -1, 1, -1, 1, -1, 0};
for (int n = 0; n < 8; ++n) {
// Prepara para empezar a dibujar en la textura de juego
screen->start();
deathShake.active = true;
deathShake.step = 0;
deathShake.lastStepTicks = SDL_GetTicks();
}
// Limpia la pantalla
screen->clean(bgColor);
// Actualiza el efecto de agitación intensa
void Game::updateDeathShake() {
if (!deathShake.active) return;
// Dibuja los objetos
buildingsSprite->setPosX(0);
buildingsSprite->setWidth(1);
buildingsSprite->setSpriteClip(0, 0, 1, 160);
renderBackground();
buildingsSprite->setPosX(255);
buildingsSprite->setSpriteClip(255, 0, 1, 160);
buildingsSprite->render();
buildingsSprite->setPosX(v[n]);
buildingsSprite->setWidth(256);
buildingsSprite->setSpriteClip(0, 0, 256, 160);
buildingsSprite->render();
grassSprite->render();
renderBalloons();
renderBullets();
renderItems();
renderPlayers();
renderScoreBoard();
// Vuelca el contenido del renderizador en pantalla
screen->blit();
SDL_Delay(50);
Uint32 now = SDL_GetTicks();
if (now - deathShake.lastStepTicks >= 50) {
deathShake.lastStepTicks = now;
deathShake.step++;
if (deathShake.step >= 8) {
deathShake.active = false;
}
}
}
// Indica si el efecto de agitación intensa está activo
bool Game::isDeathShaking() {
return deathShake.active;
}
// Bucle para el juego
void Game::run() {
while (section->name == SECTION_PROG_GAME) {