respawn de nau i invulnerabilitat

This commit is contained in:
2025-12-10 11:35:45 +01:00
parent 9a5adcbcc5
commit 3b638f4715
5 changed files with 55 additions and 8 deletions

View File

@@ -105,6 +105,17 @@ constexpr float ENEMY_RADIUS = 20.0f;
constexpr float BULLET_RADIUS = 3.0f; constexpr float BULLET_RADIUS = 3.0f;
} // namespace Entities } // 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) // Game rules (lives, respawn, game over)
namespace Game { namespace Game {
constexpr int STARTING_LIVES = 3; // Initial lives constexpr int STARTING_LIVES = 3; // Initial lives

View File

@@ -20,7 +20,8 @@ Nau::Nau(SDL_Renderer* renderer)
angle_(0.0f), angle_(0.0f),
velocitat_(0.0f), velocitat_(0.0f),
esta_tocada_(false), esta_tocada_(false),
brightness_(Defaults::Brightness::NAU) { brightness_(Defaults::Brightness::NAU),
invulnerable_timer_(0.0f) {
// [NUEVO] Carregar forma compartida des de fitxer // [NUEVO] Carregar forma compartida des de fitxer
forma_ = Graphics::ShapeLoader::load("ship.shp"); 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) // Inicialització de la nau (triangle)
// Basat en el codi Pascal original: lines 380-384 // Basat en el codi Pascal original: lines 380-384
// Copiat de joc_asteroides.cpp línies 30-44 // Copiat de joc_asteroides.cpp línies 30-44
@@ -52,6 +53,14 @@ void Nau::inicialitzar(const Punt* spawn_point) {
// Estat inicial // Estat inicial
angle_ = 0.0f; angle_ = 0.0f;
velocitat_ = 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; esta_tocada_ = false;
} }
@@ -90,6 +99,14 @@ void Nau::actualitzar(float delta_time) {
if (esta_tocada_) if (esta_tocada_)
return; 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 física (moviment + fricció)
aplicar_fisica(delta_time); aplicar_fisica(delta_time);
} }
@@ -99,6 +116,19 @@ void Nau::dibuixar() const {
if (esta_tocada_) if (esta_tocada_)
return; 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_) if (!forma_)
return; return;

View File

@@ -17,7 +17,7 @@ class Nau {
: renderer_(nullptr) {} : renderer_(nullptr) {}
Nau(SDL_Renderer* renderer); 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 processar_input(float delta_time);
void actualitzar(float delta_time); void actualitzar(float delta_time);
void dibuixar() const; void dibuixar() const;
@@ -27,6 +27,7 @@ class Nau {
float get_angle() const { return angle_; } float get_angle() const { return angle_; }
bool esta_viva() const { return !esta_tocada_; } bool esta_viva() const { return !esta_tocada_; }
bool esta_tocada() const { return esta_tocada_; } bool esta_tocada() const { return esta_tocada_; }
bool es_invulnerable() const { return invulnerable_timer_ > 0.0f; }
const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; } const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; }
float get_brightness() const { return brightness_; } float get_brightness() const { return brightness_; }
Punt get_velocitat_vector() const { Punt get_velocitat_vector() const {
@@ -54,7 +55,8 @@ class Nau {
float angle_; // Angle d'orientació float angle_; // Angle d'orientació
float velocitat_; // Velocitat (px/s) float velocitat_; // Velocitat (px/s)
bool esta_tocada_; 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); void aplicar_fisica(float delta_time);
}; };

View File

@@ -214,8 +214,8 @@ void EscenaJoc::actualitzar(float delta_time) {
num_vides_--; num_vides_--;
if (num_vides_ > 0) { if (num_vides_ > 0) {
// Respawn ship // Respawn ship en posición de muerte con invulnerabilidad
nau_.inicialitzar(&punt_spawn_); nau_.inicialitzar(&punt_mort_, true);
itocado_ = 0.0f; itocado_ = 0.0f;
} else { } else {
// Game over // Game over
@@ -560,6 +560,9 @@ void EscenaJoc::tocado() {
if (itocado_ == 0.0f) { if (itocado_ == 0.0f) {
// *** PHASE 1: TRIGGER DEATH *** // *** PHASE 1: TRIGGER DEATH ***
// Guardar posición de muerte para respawn
punt_mort_ = nau_.get_centre();
// Mark ship as dead (stops rendering and input) // Mark ship as dead (stops rendering and input)
nau_.marcar_tocada(); nau_.marcar_tocada();
@@ -859,8 +862,8 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
} }
void EscenaJoc::detectar_col·lisio_nau_enemics() { void EscenaJoc::detectar_col·lisio_nau_enemics() {
// Only check collisions if ship is alive // Skip collisions if ship is dead or invulnerable
if (!nau_.esta_viva()) { if (!nau_.esta_viva() || nau_.es_invulnerable()) {
return; return;
} }

View File

@@ -56,6 +56,7 @@ class EscenaJoc {
bool game_over_; // Game over state flag bool game_over_; // Game over state flag
float game_over_timer_; // Countdown timer for auto-return (seconds) float game_over_timer_; // Countdown timer for auto-return (seconds)
Punt punt_spawn_; // Configurable spawn point Punt punt_spawn_; // Configurable spawn point
Punt punt_mort_; // Death position (for respawn)
int puntuacio_total_; // Current score int puntuacio_total_; // Current score
// Text vectorial // Text vectorial