diff --git a/source/core/defaults.hpp b/source/core/defaults.hpp index c0b6092..f66b88e 100644 --- a/source/core/defaults.hpp +++ b/source/core/defaults.hpp @@ -105,6 +105,17 @@ constexpr float ENEMY_RADIUS = 20.0f; constexpr float BULLET_RADIUS = 3.0f; } // namespace Entities +// Ship (nave del jugador) +namespace Ship { +// Invulnerabilidad post-respawn +constexpr float INVULNERABILITY_DURATION = 3.0f; // Segundos de invulnerabilidad + +// Parpadeo visual durante invulnerabilidad +constexpr float BLINK_VISIBLE_TIME = 0.1f; // Tiempo visible (segundos) +constexpr float BLINK_INVISIBLE_TIME = 0.1f; // Tiempo invisible (segundos) +// Frecuencia total: 0.2s/ciclo = 5 Hz (~15 parpadeos en 3s) +} // namespace Ship + // Game rules (lives, respawn, game over) namespace Game { constexpr int STARTING_LIVES = 3; // Initial lives diff --git a/source/game/entities/nau.cpp b/source/game/entities/nau.cpp index 25be83a..d6877ad 100644 --- a/source/game/entities/nau.cpp +++ b/source/game/entities/nau.cpp @@ -20,7 +20,8 @@ Nau::Nau(SDL_Renderer* renderer) angle_(0.0f), velocitat_(0.0f), esta_tocada_(false), - brightness_(Defaults::Brightness::NAU) { + brightness_(Defaults::Brightness::NAU), + invulnerable_timer_(0.0f) { // [NUEVO] Carregar forma compartida des de fitxer forma_ = Graphics::ShapeLoader::load("ship.shp"); @@ -29,7 +30,7 @@ Nau::Nau(SDL_Renderer* renderer) } } -void Nau::inicialitzar(const Punt* spawn_point) { +void Nau::inicialitzar(const Punt* spawn_point, bool activar_invulnerabilitat) { // Inicialització de la nau (triangle) // Basat en el codi Pascal original: lines 380-384 // Copiat de joc_asteroides.cpp línies 30-44 @@ -52,6 +53,14 @@ void Nau::inicialitzar(const Punt* spawn_point) { // Estat inicial angle_ = 0.0f; velocitat_ = 0.0f; + + // Activar invulnerabilidad solo si es respawn + if (activar_invulnerabilitat) { + invulnerable_timer_ = Defaults::Ship::INVULNERABILITY_DURATION; + } else { + invulnerable_timer_ = 0.0f; + } + esta_tocada_ = false; } @@ -90,6 +99,14 @@ void Nau::actualitzar(float delta_time) { if (esta_tocada_) return; + // Decrementar timer de invulnerabilidad + if (invulnerable_timer_ > 0.0f) { + invulnerable_timer_ -= delta_time; + if (invulnerable_timer_ < 0.0f) { + invulnerable_timer_ = 0.0f; + } + } + // Aplicar física (moviment + fricció) aplicar_fisica(delta_time); } @@ -99,6 +116,19 @@ void Nau::dibuixar() const { if (esta_tocada_) return; + // Si invulnerable, parpadear (toggle on/off) + if (es_invulnerable()) { + // Calcular ciclo de parpadeo + float blink_cycle = Defaults::Ship::BLINK_VISIBLE_TIME + + Defaults::Ship::BLINK_INVISIBLE_TIME; + float time_in_cycle = std::fmod(invulnerable_timer_, blink_cycle); + + // Si estamos en fase invisible, no dibujar + if (time_in_cycle < Defaults::Ship::BLINK_INVISIBLE_TIME) { + return; // No dibujar durante fase invisible + } + } + if (!forma_) return; diff --git a/source/game/entities/nau.hpp b/source/game/entities/nau.hpp index cbf7353..bf268f2 100644 --- a/source/game/entities/nau.hpp +++ b/source/game/entities/nau.hpp @@ -17,7 +17,7 @@ class Nau { : renderer_(nullptr) {} Nau(SDL_Renderer* renderer); - void inicialitzar(const Punt* spawn_point = nullptr); + void inicialitzar(const Punt* spawn_point = nullptr, bool activar_invulnerabilitat = false); void processar_input(float delta_time); void actualitzar(float delta_time); void dibuixar() const; @@ -27,6 +27,7 @@ class Nau { float get_angle() const { return angle_; } bool esta_viva() const { return !esta_tocada_; } bool esta_tocada() const { return esta_tocada_; } + bool es_invulnerable() const { return invulnerable_timer_ > 0.0f; } const std::shared_ptr& get_forma() const { return forma_; } float get_brightness() const { return brightness_; } Punt get_velocitat_vector() const { @@ -54,7 +55,8 @@ class Nau { float angle_; // Angle d'orientació float velocitat_; // Velocitat (px/s) bool esta_tocada_; - float brightness_; // Factor de brillantor (0.0-1.0) + float brightness_; // Factor de brillantor (0.0-1.0) + float invulnerable_timer_; // 0.0f = vulnerable, >0.0f = invulnerable void aplicar_fisica(float delta_time); }; diff --git a/source/game/escenes/escena_joc.cpp b/source/game/escenes/escena_joc.cpp index da413d6..9c8ac26 100644 --- a/source/game/escenes/escena_joc.cpp +++ b/source/game/escenes/escena_joc.cpp @@ -214,8 +214,8 @@ void EscenaJoc::actualitzar(float delta_time) { num_vides_--; if (num_vides_ > 0) { - // Respawn ship - nau_.inicialitzar(&punt_spawn_); + // Respawn ship en posición de muerte con invulnerabilidad + nau_.inicialitzar(&punt_mort_, true); itocado_ = 0.0f; } else { // Game over @@ -560,6 +560,9 @@ void EscenaJoc::tocado() { if (itocado_ == 0.0f) { // *** PHASE 1: TRIGGER DEATH *** + // Guardar posición de muerte para respawn + punt_mort_ = nau_.get_centre(); + // Mark ship as dead (stops rendering and input) nau_.marcar_tocada(); @@ -859,8 +862,8 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() { } void EscenaJoc::detectar_col·lisio_nau_enemics() { - // Only check collisions if ship is alive - if (!nau_.esta_viva()) { + // Skip collisions if ship is dead or invulnerable + if (!nau_.esta_viva() || nau_.es_invulnerable()) { return; } diff --git a/source/game/escenes/escena_joc.hpp b/source/game/escenes/escena_joc.hpp index f131a50..f933a86 100644 --- a/source/game/escenes/escena_joc.hpp +++ b/source/game/escenes/escena_joc.hpp @@ -56,6 +56,7 @@ class EscenaJoc { bool game_over_; // Game over state flag float game_over_timer_; // Countdown timer for auto-return (seconds) Punt punt_spawn_; // Configurable spawn point + Punt punt_mort_; // Death position (for respawn) int puntuacio_total_; // Current score // Text vectorial