afegida logica de continues
fix: el text no centrava correctament en horitzontal
This commit is contained in:
@@ -153,7 +153,10 @@ void EscenaJoc::inicialitzar() {
|
||||
// Initialize lives and game over state (independent lives per player)
|
||||
vides_per_jugador_[0] = Defaults::Game::STARTING_LIVES;
|
||||
vides_per_jugador_[1] = Defaults::Game::STARTING_LIVES;
|
||||
game_over_ = false;
|
||||
estat_game_over_ = EstatGameOver::NONE;
|
||||
continue_counter_ = 0;
|
||||
continue_tick_timer_ = 0.0f;
|
||||
continues_usados_ = 0;
|
||||
game_over_timer_ = 0.0f;
|
||||
|
||||
// Initialize scores (separate per player)
|
||||
@@ -206,7 +209,7 @@ void EscenaJoc::inicialitzar() {
|
||||
|
||||
void EscenaJoc::actualitzar(float delta_time) {
|
||||
// Processar disparos (state-based, no event-based)
|
||||
if (!game_over_) {
|
||||
if (estat_game_over_ == EstatGameOver::NONE) {
|
||||
auto* input = Input::get();
|
||||
|
||||
// Jugador 1 dispara (només si està actiu)
|
||||
@@ -222,10 +225,42 @@ void EscenaJoc::actualitzar(float delta_time) {
|
||||
disparar_bala(1);
|
||||
}
|
||||
}
|
||||
|
||||
// [NEW] Allow mid-game join: inactive player presses START
|
||||
// P2 can join if only P1 is active
|
||||
if (config_partida_.jugador1_actiu && !config_partida_.jugador2_actiu) {
|
||||
if (input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
unir_jugador(1);
|
||||
}
|
||||
}
|
||||
|
||||
// P1 can join if only P2 is active
|
||||
if (!config_partida_.jugador1_actiu && config_partida_.jugador2_actiu) {
|
||||
if (input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
unir_jugador(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check game over state first
|
||||
if (game_over_) {
|
||||
// Handle CONTINUE screen
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
actualitzar_continue(delta_time);
|
||||
processar_input_continue();
|
||||
|
||||
// Still update enemies, bullets, and effects during continue screen
|
||||
for (auto& enemy : orni_) {
|
||||
enemy.actualitzar(delta_time);
|
||||
}
|
||||
for (auto& bala : bales_) {
|
||||
bala.actualitzar(delta_time);
|
||||
}
|
||||
debris_manager_.actualitzar(delta_time);
|
||||
gestor_puntuacio_.actualitzar(delta_time);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle final GAME OVER state
|
||||
if (estat_game_over_ == EstatGameOver::GAME_OVER) {
|
||||
// Game over: only update timer, enemies, bullets, and debris
|
||||
game_over_timer_ -= delta_time;
|
||||
|
||||
@@ -277,13 +312,14 @@ void EscenaJoc::actualitzar(float delta_time) {
|
||||
// Set sentinel value to prevent re-entering this block
|
||||
itocado_per_jugador_[i] = 999.0f;
|
||||
|
||||
// Check if ALL ACTIVE players are dead (game over)
|
||||
// Check if ALL ACTIVE players are dead (trigger continue screen)
|
||||
bool p1_dead = !config_partida_.jugador1_actiu || vides_per_jugador_[0] <= 0;
|
||||
bool p2_dead = !config_partida_.jugador2_actiu || vides_per_jugador_[1] <= 0;
|
||||
|
||||
if (p1_dead && p2_dead) {
|
||||
game_over_ = true;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
estat_game_over_ = EstatGameOver::CONTINUE;
|
||||
continue_counter_ = Defaults::Game::CONTINUE_COUNT_START;
|
||||
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,8 +486,30 @@ void EscenaJoc::actualitzar(float delta_time) {
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar() {
|
||||
// Check game over state
|
||||
if (game_over_) {
|
||||
// Handle CONTINUE screen
|
||||
if (estat_game_over_ == EstatGameOver::CONTINUE) {
|
||||
// Draw game background elements first
|
||||
dibuixar_marges();
|
||||
|
||||
for (const auto& enemy : orni_) {
|
||||
enemy.dibuixar();
|
||||
}
|
||||
|
||||
for (const auto& bala : bales_) {
|
||||
bala.dibuixar();
|
||||
}
|
||||
|
||||
debris_manager_.dibuixar();
|
||||
gestor_puntuacio_.dibuixar();
|
||||
dibuixar_marcador();
|
||||
|
||||
// Draw CONTINUE screen overlay
|
||||
dibuixar_continue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle final GAME OVER state
|
||||
if (estat_game_over_ == EstatGameOver::GAME_OVER) {
|
||||
// Game over: draw enemies, bullets, debris, and "GAME OVER" text
|
||||
dibuixar_marges();
|
||||
|
||||
@@ -1121,3 +1179,169 @@ void EscenaJoc::disparar_bala(uint8_t player_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== CONTINUE & JOIN SYSTEM ====================
|
||||
|
||||
void EscenaJoc::actualitzar_continue(float delta_time) {
|
||||
continue_tick_timer_ -= delta_time;
|
||||
|
||||
if (continue_tick_timer_ <= 0.0f) {
|
||||
continue_counter_--;
|
||||
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
|
||||
|
||||
// Play tick sound
|
||||
Audio::get()->playSound("continue_tick");
|
||||
|
||||
if (continue_counter_ <= 0) {
|
||||
// Timeout → final game over
|
||||
estat_game_over_ = EstatGameOver::GAME_OVER;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::processar_input_continue() {
|
||||
auto* input = Input::get();
|
||||
|
||||
// Check START for both players
|
||||
bool p1_start = input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
|
||||
bool p2_start = input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
|
||||
|
||||
if (p1_start || p2_start) {
|
||||
// Check continue limit (skip if infinite continues)
|
||||
if (!Defaults::Game::INFINITE_CONTINUES && continues_usados_ >= Defaults::Game::MAX_CONTINUES) {
|
||||
// Max continues reached → final game over
|
||||
estat_game_over_ = EstatGameOver::GAME_OVER;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only increment if not infinite
|
||||
if (!Defaults::Game::INFINITE_CONTINUES) {
|
||||
continues_usados_++;
|
||||
}
|
||||
|
||||
// Determine which player(s) to revive
|
||||
uint8_t player_to_revive = p1_start ? 0 : 1;
|
||||
|
||||
// Reset score and lives (KEEP level and enemies!)
|
||||
puntuacio_per_jugador_[player_to_revive] = 0;
|
||||
vides_per_jugador_[player_to_revive] = Defaults::Game::STARTING_LIVES;
|
||||
itocado_per_jugador_[player_to_revive] = 0.0f;
|
||||
|
||||
// Activate player if not already
|
||||
if (player_to_revive == 0) {
|
||||
config_partida_.jugador1_actiu = true;
|
||||
} else {
|
||||
config_partida_.jugador2_actiu = true;
|
||||
}
|
||||
|
||||
// Spawn with invulnerability
|
||||
Punt spawn_pos = obtenir_punt_spawn(player_to_revive);
|
||||
naus_[player_to_revive].inicialitzar(&spawn_pos, true);
|
||||
|
||||
// Check if other player wants to continue too
|
||||
if (p1_start && p2_start) {
|
||||
uint8_t other_player = 1;
|
||||
puntuacio_per_jugador_[other_player] = 0;
|
||||
vides_per_jugador_[other_player] = Defaults::Game::STARTING_LIVES;
|
||||
itocado_per_jugador_[other_player] = 0.0f;
|
||||
config_partida_.jugador2_actiu = true;
|
||||
Punt spawn_pos2 = obtenir_punt_spawn(other_player);
|
||||
naus_[other_player].inicialitzar(&spawn_pos2, true);
|
||||
}
|
||||
|
||||
// Resume game
|
||||
estat_game_over_ = EstatGameOver::NONE;
|
||||
continue_counter_ = 0;
|
||||
continue_tick_timer_ = 0.0f;
|
||||
|
||||
// Play continue confirmation sound
|
||||
Audio::get()->playSound("continue_confirm");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check THRUST/FIRE to accelerate countdown (DO_NOT_ALLOW_REPEAT to avoid spam)
|
||||
bool thrust_p1 = input->checkActionPlayer1(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT);
|
||||
bool thrust_p2 = input->checkActionPlayer2(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT);
|
||||
bool fire_p1 = input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
|
||||
bool fire_p2 = input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
|
||||
|
||||
if (thrust_p1 || thrust_p2 || fire_p1 || fire_p2) {
|
||||
continue_counter_--;
|
||||
|
||||
// Play tick sound on manual decrement
|
||||
Audio::get()->playSound("continue_tick");
|
||||
|
||||
if (continue_counter_ <= 0) {
|
||||
estat_game_over_ = EstatGameOver::GAME_OVER;
|
||||
game_over_timer_ = Defaults::Game::GAME_OVER_DURATION;
|
||||
}
|
||||
|
||||
// Reset timer to prevent double-decrement
|
||||
continue_tick_timer_ = Defaults::Game::CONTINUE_TICK_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::dibuixar_continue() {
|
||||
const SDL_FRect& play_area = Defaults::Zones::PLAYAREA;
|
||||
constexpr float spacing = 4.0f;
|
||||
|
||||
// "CONTINUE" text (using constants)
|
||||
const std::string continue_text = "CONTINUE";
|
||||
float escala_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_SCALE;
|
||||
float y_ratio_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_Y_RATIO;
|
||||
|
||||
float text_width_continue = text_.get_text_width(continue_text, escala_continue, spacing);
|
||||
float x_continue = play_area.x + (play_area.w - text_width_continue) / 2.0f;
|
||||
float y_continue = play_area.y + play_area.h * y_ratio_continue;
|
||||
|
||||
text_.render(continue_text, {x_continue, y_continue}, escala_continue, spacing);
|
||||
|
||||
// Countdown number (using constants)
|
||||
const std::string counter_str = std::to_string(continue_counter_);
|
||||
float escala_counter = Defaults::Game::ContinueScreen::COUNTER_TEXT_SCALE;
|
||||
float y_ratio_counter = Defaults::Game::ContinueScreen::COUNTER_TEXT_Y_RATIO;
|
||||
|
||||
float text_width_counter = text_.get_text_width(counter_str, escala_counter, spacing);
|
||||
float x_counter = play_area.x + (play_area.w - text_width_counter) / 2.0f;
|
||||
float y_counter = play_area.y + play_area.h * y_ratio_counter;
|
||||
|
||||
text_.render(counter_str, {x_counter, y_counter}, escala_counter, spacing);
|
||||
|
||||
// "CONTINUES LEFT" (conditional + using constants)
|
||||
if (!Defaults::Game::INFINITE_CONTINUES) {
|
||||
const std::string continues_text = "CONTINUES LEFT: " + std::to_string(Defaults::Game::MAX_CONTINUES - continues_usados_);
|
||||
float escala_info = Defaults::Game::ContinueScreen::INFO_TEXT_SCALE;
|
||||
float y_ratio_info = Defaults::Game::ContinueScreen::INFO_TEXT_Y_RATIO;
|
||||
|
||||
float text_width_info = text_.get_text_width(continues_text, escala_info, spacing);
|
||||
float x_info = play_area.x + (play_area.w - text_width_info) / 2.0f;
|
||||
float y_info = play_area.y + play_area.h * y_ratio_info;
|
||||
|
||||
text_.render(continues_text, {x_info, y_info}, escala_info, spacing);
|
||||
}
|
||||
}
|
||||
|
||||
void EscenaJoc::unir_jugador(uint8_t player_id) {
|
||||
// Activate player
|
||||
if (player_id == 0) {
|
||||
config_partida_.jugador1_actiu = true;
|
||||
} else {
|
||||
config_partida_.jugador2_actiu = true;
|
||||
}
|
||||
|
||||
// Reset stats
|
||||
vides_per_jugador_[player_id] = Defaults::Game::STARTING_LIVES;
|
||||
puntuacio_per_jugador_[player_id] = 0;
|
||||
itocado_per_jugador_[player_id] = 0.0f;
|
||||
|
||||
// Spawn with invulnerability
|
||||
Punt spawn_pos = obtenir_punt_spawn(player_id);
|
||||
naus_[player_id].inicialitzar(&spawn_pos, true);
|
||||
|
||||
// No visual message, just spawn (per user requirement)
|
||||
|
||||
std::cout << "[EscenaJoc] Jugador " << (int)(player_id + 1) << " s'ha unit a la partida!" << std::endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user