refactor: renombra jugador*/zona/radi/MARGE/origen/letra residuals a anglès

This commit is contained in:
2026-05-24 08:09:41 +02:00
parent d36ad7d1c5
commit 252e881e93
22 changed files with 265 additions and 265 deletions
+2 -2
View File
@@ -9,8 +9,8 @@ namespace Defaults::FX::Glow {
// Neon glow per outline gruixut, aplicat automàticament per renderShape. // Neon glow per outline gruixut, aplicat automàticament per renderShape.
// Els gruixos d'halo són RÀTIOS del bounding_radius de la shape (escalat // Els gruixos d'halo són RÀTIOS del bounding_radius de la shape (escalat
// per scale), de manera que un pentàgon (radi 20) té halo gros i una bala // per scale), de manera que un pentàgon (radius 20) té halo gros i una bala
// (radi 3) té halo subtil. El core (últim pass) usa el gruix de línia // (radius 3) té halo subtil. El core (últim pass) usa el gruix de línia
// global (1.5px) — no escala amb la shape. // global (1.5px) — no escala amb la shape.
// //
// Cap superior: si la shape és molt gran (logos del títol, intro), el // Cap superior: si la shape és molt gran (logos del títol, intro), el
+1 -1
View File
@@ -59,7 +59,7 @@ namespace Defaults::Game {
constexpr float INIT_HUD_SHIP2_RATIO_INIT = 0.20F; constexpr float INIT_HUD_SHIP2_RATIO_INIT = 0.20F;
constexpr float INIT_HUD_SHIP2_RATIO_END = 1.0F; constexpr float INIT_HUD_SHIP2_RATIO_END = 1.0F;
// Posición inicial de la nave en INIT_HUD (75% de altura de zona de juego) // Posición inicial de la nave en INIT_HUD (75% de altura de zone de juego)
constexpr float INIT_HUD_SHIP_START_Y_RATIO = 0.75F; // 75% desde el top de PLAYAREA constexpr float INIT_HUD_SHIP_START_Y_RATIO = 0.75F; // 75% desde el top de PLAYAREA
// Spawn positions (distribución horizontal para 2 jugadores) // Spawn positions (distribución horizontal para 2 jugadores)
+1 -1
View File
@@ -68,7 +68,7 @@ namespace Defaults::Title {
constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotante: scale base constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotante: scale base
// Offset de entrada (ajustat automáticoament a l'scale) // Offset de entrada (ajustat automáticoament a l'scale)
// Fórmula: (radi màxim de la ship * scale de entrada) + margen // Fórmula: (radius màxim de la ship * scale de entrada) + margen
constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN; constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN;
// Vec2 de fuga (centro para l'animación de salida) // Vec2 de fuga (centro para l'animación de salida)
+10 -10
View File
@@ -23,12 +23,12 @@ namespace Graphics {
} }
void Border::bumpAt(Vec2 contact_point, float strength) { void Border::bumpAt(Vec2 contact_point, float strength) {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const std::array<float, SIDE_COUNT> DISTANCES = { const std::array<float, SIDE_COUNT> DISTANCES = {
/* TOP */ std::abs(contact_point.y - zona.y), /* TOP */ std::abs(contact_point.y - zone.y),
/* RIGHT */ std::abs((zona.x + zona.w) - contact_point.x), /* RIGHT */ std::abs((zone.x + zone.w) - contact_point.x),
/* BOTTOM */ std::abs((zona.y + zona.h) - contact_point.y), /* BOTTOM */ std::abs((zone.y + zone.h) - contact_point.y),
/* LEFT */ std::abs(contact_point.x - zona.x)}; /* LEFT */ std::abs(contact_point.x - zone.x)};
int closest_idx = 0; int closest_idx = 0;
float closest_dist = DISTANCES[0]; float closest_dist = DISTANCES[0];
@@ -71,11 +71,11 @@ namespace Graphics {
} // namespace } // namespace
void Border::draw() const { void Border::draw() const {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const int X1 = static_cast<int>(zona.x); const int X1 = static_cast<int>(zone.x);
const int Y1 = static_cast<int>(zona.y); const int Y1 = static_cast<int>(zone.y);
const int X2 = static_cast<int>(zona.x + zona.w); const int X2 = static_cast<int>(zone.x + zone.w);
const int Y2 = static_cast<int>(zona.y + zona.h); const int Y2 = static_cast<int>(zone.y + zone.h);
const int OFF_TOP = static_cast<int>(sides_[SIDE_TOP].displacement_px); const int OFF_TOP = static_cast<int>(sides_[SIDE_TOP].displacement_px);
const int OFF_RIGHT = static_cast<int>(sides_[SIDE_RIGHT].displacement_px); const int OFF_RIGHT = static_cast<int>(sides_[SIDE_RIGHT].displacement_px);
+9 -9
View File
@@ -141,9 +141,9 @@ namespace Graphics {
} }
void Playfield::buildLines() { void Playfield::buildLines() {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const float CELL_W = zona.w / static_cast<float>(Defaults::Playfield::COLUMNS); const float CELL_W = zone.w / static_cast<float>(Defaults::Playfield::COLUMNS);
const float CELL_H = zona.h / static_cast<float>(Defaults::Playfield::ROWS); const float CELL_H = zone.h / static_cast<float>(Defaults::Playfield::ROWS);
const float SUB_W = CELL_W / static_cast<float>(Defaults::Playfield::SUBDIVISIONS); const float SUB_W = CELL_W / static_cast<float>(Defaults::Playfield::SUBDIVISIONS);
const float SUB_H = CELL_H / static_cast<float>(Defaults::Playfield::SUBDIVISIONS); const float SUB_H = CELL_H / static_cast<float>(Defaults::Playfield::SUBDIVISIONS);
const int SUB_VERTS = Defaults::Playfield::COLUMNS * Defaults::Playfield::SUBDIVISIONS; const int SUB_VERTS = Defaults::Playfield::COLUMNS * Defaults::Playfield::SUBDIVISIONS;
@@ -154,14 +154,14 @@ namespace Graphics {
// Verticals: posicions i ∈ [1, SUB_VERTS-1]. // Verticals: posicions i ∈ [1, SUB_VERTS-1].
for (int i = 1; i < SUB_VERTS; i++) { for (int i = 1; i < SUB_VERTS; i++) {
const float X = zona.x + (static_cast<float>(i) * SUB_W); const float X = zone.x + (static_cast<float>(i) * SUB_W);
const bool IS_MAIN = (i % Defaults::Playfield::SUBDIVISIONS) == 0; const bool IS_MAIN = (i % Defaults::Playfield::SUBDIVISIONS) == 0;
const float BRIGHTNESS = IS_MAIN const float BRIGHTNESS = IS_MAIN
? Defaults::Playfield::GRID_BRIGHTNESS ? Defaults::Playfield::GRID_BRIGHTNESS
: Defaults::Playfield::SUBGRID_BRIGHTNESS; : Defaults::Playfield::SUBGRID_BRIGHTNESS;
verticals.push_back(Line{ verticals.push_back(Line{
.start = {.x = X, .y = zona.y}, .start = {.x = X, .y = zone.y},
.end = {.x = X, .y = zona.y + zona.h}, .end = {.x = X, .y = zone.y + zone.h},
.brightness = BRIGHTNESS, .brightness = BRIGHTNESS,
.spawn_time_s = 0.0F, .spawn_time_s = 0.0F,
.is_vertical = true}); .is_vertical = true});
@@ -169,14 +169,14 @@ namespace Graphics {
// Horitzontals: posicions j ∈ [1, SUB_HORIZ-1]. // Horitzontals: posicions j ∈ [1, SUB_HORIZ-1].
for (int j = 1; j < SUB_HORIZ; j++) { for (int j = 1; j < SUB_HORIZ; j++) {
const float Y = zona.y + (static_cast<float>(j) * SUB_H); const float Y = zone.y + (static_cast<float>(j) * SUB_H);
const bool IS_MAIN = (j % Defaults::Playfield::SUBDIVISIONS) == 0; const bool IS_MAIN = (j % Defaults::Playfield::SUBDIVISIONS) == 0;
const float BRIGHTNESS = IS_MAIN const float BRIGHTNESS = IS_MAIN
? Defaults::Playfield::GRID_BRIGHTNESS ? Defaults::Playfield::GRID_BRIGHTNESS
: Defaults::Playfield::SUBGRID_BRIGHTNESS; : Defaults::Playfield::SUBGRID_BRIGHTNESS;
horizontals.push_back(Line{ horizontals.push_back(Line{
.start = {.x = zona.x, .y = Y}, .start = {.x = zone.x, .y = Y},
.end = {.x = zona.x + zona.w, .y = Y}, .end = {.x = zone.x + zone.w, .y = Y},
.brightness = BRIGHTNESS, .brightness = BRIGHTNESS,
.spawn_time_s = 0.0F, .spawn_time_s = 0.0F,
.is_vertical = false}); .is_vertical = false});
+12 -12
View File
@@ -25,11 +25,11 @@ namespace Graphics {
} }
void StarfieldParallax::buildStars() { void StarfieldParallax::buildStars() {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const float MIN_X = zona.x; const float MIN_X = zone.x;
const float MAX_X = zona.x + zona.w; const float MAX_X = zone.x + zone.w;
const float MIN_Y = zona.y; const float MIN_Y = zone.y;
const float MAX_Y = zona.y + zona.h; const float MAX_Y = zone.y + zone.h;
// Color únic per a totes les estrelles: el mateix blanc-blau gel // Color únic per a totes les estrelles: el mateix blanc-blau gel
// del starfield del títol (Defaults::Title::Colors::STARFIELD). // del starfield del títol (Defaults::Title::Colors::STARFIELD).
@@ -89,13 +89,13 @@ namespace Graphics {
} }
void StarfieldParallax::update(float delta_time, Vec2 world_velocity) { void StarfieldParallax::update(float delta_time, Vec2 world_velocity) {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const float MIN_X = zona.x; const float MIN_X = zone.x;
const float MAX_X = zona.x + zona.w; const float MAX_X = zone.x + zone.w;
const float MIN_Y = zona.y; const float MIN_Y = zone.y;
const float MAX_Y = zona.y + zona.h; const float MAX_Y = zone.y + zone.h;
const float W = zona.w; const float W = zone.w;
const float H = zona.h; const float H = zone.h;
for (auto& star : stars_) { for (auto& star : stars_) {
const float FACTOR = layerParallax(star.layer); const float FACTOR = layerParallax(star.layer);
+3 -3
View File
@@ -17,7 +17,7 @@ namespace Physics {
return false; return false;
} }
// Calcular radi combinat (con amplificador per hitbox generós) // Calcular radius combinat (con amplificador per hitbox generós)
float suma_radis = (a.getCollisionRadius() + b.getCollisionRadius()) * amplifier; float suma_radis = (a.getCollisionRadius() + b.getCollisionRadius()) * amplifier;
float suma_radis_sq = suma_radis * suma_radis; float suma_radis_sq = suma_radis * suma_radis;
@@ -31,8 +31,8 @@ namespace Physics {
return dist_sq <= suma_radis_sq; return dist_sq <= suma_radis_sq;
} }
// Swept collision: una entitat mòbil (radi r_a) s'ha desplaçat de p0 a p1 aquest // Swept collision: una entitat mòbil (radius r_a) s'ha desplaçat de p0 a p1 aquest
// frame. Comprova si el segment expandit pel radi conjunt (r_a + radi de b, amb // frame. Comprova si el segment expandit pel radius conjunt (r_a + radius de b, amb
// amplificador) toca el cercle de l'entity b. Equival al check discrete quan // amplificador) toca el cercle de l'entity b. Equival al check discrete quan
// p0 == p1 (sense moviment). Evita tunneling a velocitats altes. // p0 == p1 (sense moviment). Evita tunneling a velocitats altes.
inline auto checkCollisionSwept(const Vec2& p0, const Vec2& p1, float r_a, const Entities::Entity& b, float amplifier = 1.0F) -> bool { inline auto checkCollisionSwept(const Vec2& p0, const Vec2& p1, float r_a, const Entities::Entity& b, float amplifier = 1.0F) -> bool {
+17 -17
View File
@@ -4,52 +4,52 @@
namespace GameConfig { namespace GameConfig {
// Mode de juego // Mode de juego
enum class Mode : std::uint8_t { enum class Mode : std::uint8_t {
NORMAL, // Partida normal NORMAL, // Partida normal
DEMO // Mode demostració (futur) DEMO // Mode demostració (futur)
}; };
// Configuración de una match // Configuración de una match
struct MatchConfig { struct MatchConfig {
bool jugador1_actiu{false}; // Es active el player 1? bool player1_active{false}; // Es active el player 1?
bool jugador2_actiu{false}; // Es active el player 2? bool player2_active{false}; // Es active el player 2?
Mode mode{Mode::NORMAL}; // Mode de juego Mode mode{Mode::NORMAL}; // Mode de juego
// Métodos auxiliars // Métodos auxiliars
// Retorna true si solo hay un player active // Retorna true si solo hay un player active
[[nodiscard]] auto isSinglePlayer() const -> bool { [[nodiscard]] auto isSinglePlayer() const -> bool {
return (jugador1_actiu && !jugador2_actiu) || return (player1_active && !player2_active) ||
(!jugador1_actiu && jugador2_actiu); (!player1_active && player2_active);
} }
// Retorna true si hay dos jugadors active // Retorna true si hay dos jugadors active
[[nodiscard]] auto isCoop() const -> bool { [[nodiscard]] auto isCoop() const -> bool {
return jugador1_actiu && jugador2_actiu; return player1_active && player2_active;
} }
// Retorna true si no hay sin player active // Retorna true si no hay sin player active
[[nodiscard]] auto hasNoPlayers() const -> bool { [[nodiscard]] auto hasNoPlayers() const -> bool {
return !jugador1_actiu && !jugador2_actiu; return !player1_active && !player2_active;
} }
// Compte de jugadors active (0, 1 o 2) // Compte de jugadors active (0, 1 o 2)
[[nodiscard]] auto getPlayerCount() const -> uint8_t { [[nodiscard]] auto getPlayerCount() const -> uint8_t {
return (jugador1_actiu ? 1 : 0) + (jugador2_actiu ? 1 : 0); return (player1_active ? 1 : 0) + (player2_active ? 1 : 0);
} }
// Retorna l'ID de l'únic player active (0 o 1) // Retorna l'ID de l'únic player active (0 o 1)
// Solo vàlid si es_un_jugador() retorna true // Solo vàlid si es_un_jugador() retorna true
[[nodiscard]] auto getSinglePlayerId() const -> uint8_t { [[nodiscard]] auto getSinglePlayerId() const -> uint8_t {
if (jugador1_actiu && !jugador2_actiu) { if (player1_active && !player2_active) {
return 0; return 0;
} }
if (!jugador1_actiu && jugador2_actiu) { if (!player1_active && player2_active) {
return 1; return 1;
} }
return 0; // Fallback (necesario comprovar es_un_jugador() primer) return 0; // Fallback (necesario comprovar es_un_jugador() primer)
} }
}; };
} // namespace GameConfig } // namespace GameConfig
+18 -18
View File
@@ -12,35 +12,35 @@ namespace Constants {
// Matemàtiques // Matemàtiques
constexpr float PI = Defaults::Math::PI; constexpr float PI = Defaults::Math::PI;
// Helpers per comprovar límits de zona // Helpers per comprovar límits de zone
inline auto isInPlayArea(float x, float y) -> bool { inline auto isInPlayArea(float x, float y) -> bool {
const SDL_FPoint POINT = {x, y}; const SDL_FPoint POINT = {x, y};
return SDL_PointInRectFloat(&POINT, &Defaults::Zones::PLAYAREA); return SDL_PointInRectFloat(&POINT, &Defaults::Zones::PLAYAREA);
} }
inline void getPlayAreaBounds(float& min_x, float& max_x, float& min_y, float& max_y) { inline void getPlayAreaBounds(float& min_x, float& max_x, float& min_y, float& max_y) {
const auto& zona = Defaults::Zones::PLAYAREA; const auto& zone = Defaults::Zones::PLAYAREA;
min_x = zona.x; min_x = zone.x;
max_x = zona.x + zona.w; max_x = zone.x + zone.w;
min_y = zona.y; min_y = zone.y;
max_y = zona.y + zona.h; max_y = zone.y + zone.h;
} }
// Obtenir límits segurs (compensant radi de l'entidad) // Obtenir límits segurs (compensant radius de l'entidad)
inline void getSafePlayAreaBounds(float radi, float& min_x, float& max_x, float& min_y, float& max_y) { inline void getSafePlayAreaBounds(float radius, float& min_x, float& max_x, float& min_y, float& max_y) {
const auto& zona = Defaults::Zones::PLAYAREA; const auto& zone = Defaults::Zones::PLAYAREA;
constexpr float MARGE_SEGURETAT = 10.0F; // Safety margin constexpr float SAFETY_MARGIN = 10.0F; // Safety margin
min_x = zona.x + radi + MARGE_SEGURETAT; min_x = zone.x + radius + SAFETY_MARGIN;
max_x = zona.x + zona.w - radi - MARGE_SEGURETAT; max_x = zone.x + zone.w - radius - SAFETY_MARGIN;
min_y = zona.y + radi + MARGE_SEGURETAT; min_y = zone.y + radius + SAFETY_MARGIN;
max_y = zona.y + zona.h - radi - MARGE_SEGURETAT; max_y = zone.y + zone.h - radius - SAFETY_MARGIN;
} }
// Obtenir centro de l'àrea de juego // Obtenir centro de l'àrea de juego
inline void getPlayAreaCenter(float& centre_x, float& centre_y) { inline void getPlayAreaCenter(float& center_x, float& center_y) {
const auto& zona = Defaults::Zones::PLAYAREA; const auto& zone = Defaults::Zones::PLAYAREA;
centre_x = zona.x + (zona.w / 2.0F); center_x = zone.x + (zone.w / 2.0F);
centre_y = zona.y + (zona.h / 2.0F); center_y = zone.y + (zone.h / 2.0F);
} }
} // namespace Constants } // namespace Constants
+3 -3
View File
@@ -61,7 +61,7 @@ namespace Effects {
} }
} }
void FireworkManager::spawn(const Vec2& origen, void FireworkManager::spawn(const Vec2& origin,
SDL_Color color, SDL_Color color,
float initial_speed, float initial_speed,
int n_points, int n_points,
@@ -74,7 +74,7 @@ namespace Effects {
// Notificar als subscriptors (playfield pulses, etc.). // Notificar als subscriptors (playfield pulses, etc.).
if (spawn_callback_) { if (spawn_callback_) {
spawn_callback_(origen); spawn_callback_(origin);
} }
const float ANGLE_STEP = 2.0F * Defaults::Math::PI / static_cast<float>(n_points); const float ANGLE_STEP = 2.0F * Defaults::Math::PI / static_cast<float>(n_points);
@@ -94,7 +94,7 @@ namespace Effects {
const float SPEED = const float SPEED =
initial_speed + (randSigned() * Defaults::FX::Firework::SPEED_VARIATION); initial_speed + (randSigned() * Defaults::FX::Firework::SPEED_VARIATION);
fw->head = origen; fw->head = origin;
fw->velocity = {.x = std::cos(ANGLE) * SPEED, .y = std::sin(ANGLE) * SPEED}; fw->velocity = {.x = std::cos(ANGLE) * SPEED, .y = std::sin(ANGLE) * SPEED};
fw->acceleration = Defaults::FX::Firework::FRICTION; fw->acceleration = Defaults::FX::Firework::FRICTION;
+2 -2
View File
@@ -21,7 +21,7 @@ namespace Effects {
class FireworkManager { class FireworkManager {
public: public:
// Notificació opcional cada vegada que es genera un burst. // Notificació opcional cada vegada que es genera un burst.
using SpawnCallback = std::function<void(Vec2 origen)>; using SpawnCallback = std::function<void(Vec2 origin)>;
explicit FireworkManager(Rendering::Renderer* renderer); explicit FireworkManager(Rendering::Renderer* renderer);
@@ -37,7 +37,7 @@ namespace Effects {
// initial_brightness: 0..1. // initial_brightness: 0..1.
// glow: si true, cada partícula es renderitza amb halo neon. // glow: si true, cada partícula es renderitza amb halo neon.
// glow_color: color del halo. Si alpha==0, agafa el color de la línia. // glow_color: color del halo. Si alpha==0, agafa el color de la línia.
void spawn(const Vec2& origen, void spawn(const Vec2& origin,
SDL_Color color = Defaults::FX::Firework::DEFAULT_COLOR, SDL_Color color = Defaults::FX::Firework::DEFAULT_COLOR,
float initial_speed = Defaults::FX::Firework::SPEED, float initial_speed = Defaults::FX::Firework::SPEED,
int n_points = Defaults::FX::Firework::N_POINTS, int n_points = Defaults::FX::Firework::N_POINTS,
+1 -1
View File
@@ -80,7 +80,7 @@ void Bullet::fire(const Vec2& position, float angle, uint8_t owner_id) {
} }
void Bullet::update(float /*delta_time*/) { void Bullet::update(float /*delta_time*/) {
// No-op: la desactivació per fora-de-zona viu a // No-op: la desactivació per fora-de-zone viu a
// Systems::Collision::desactivateOutOfBoundsBullets() perquè així té accés // Systems::Collision::desactivateOutOfBoundsBullets() perquè així té accés
// al DebrisManager i pot generar el "trencament" visual de la bala alhora. // al DebrisManager i pot generar el "trencament" visual de la bala alhora.
// El moviment l'integra PhysicsWorld; postUpdate sincronitza center_ i prev_position_. // El moviment l'integra PhysicsWorld; postUpdate sincronitza center_ i prev_position_.
+1 -1
View File
@@ -131,7 +131,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
const int RANGE_Y = static_cast<int>(max_y - min_y); const int RANGE_Y = static_cast<int>(max_y - min_y);
center_.x = static_cast<float>((std::rand() % RANGE_X) + static_cast<int>(min_x)); center_.x = static_cast<float>((std::rand() % RANGE_X) + static_cast<int>(min_x));
center_.y = static_cast<float>((std::rand() % RANGE_Y) + static_cast<int>(min_y)); center_.y = static_cast<float>((std::rand() % RANGE_Y) + static_cast<int>(min_y));
std::cout << "[Enemy] Advertencia: spawn sin zona segura tras " std::cout << "[Enemy] Advertencia: spawn sin zone segura tras "
<< Defaults::Enemies::Spawn::MAX_SPAWN_ATTEMPTS << " intentos\n"; << Defaults::Enemies::Spawn::MAX_SPAWN_ATTEMPTS << " intentos\n";
} }
} else { } else {
+4 -4
View File
@@ -44,10 +44,10 @@ void Ship::init(const Vec2* spawn_point, bool activar_invulnerabilitat) {
if (spawn_point != nullptr) { if (spawn_point != nullptr) {
center_ = *spawn_point; center_ = *spawn_point;
} else { } else {
float centre_x; float center_x;
float centre_y; float center_y;
Constants::getPlayAreaCenter(centre_x, centre_y); Constants::getPlayAreaCenter(center_x, center_y);
center_ = {.x = centre_x, .y = centre_y}; center_ = {.x = center_x, .y = center_y};
} }
// Reset orientación // Reset orientación
+48 -48
View File
@@ -38,9 +38,9 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
// Debug output de la configuración // Debug output de la configuración
std::cout << "[GameScene] Configuración de match - P1: " std::cout << "[GameScene] Configuración de match - P1: "
<< (match_config_.jugador1_actiu ? "ACTIU" : "INACTIU") << (match_config_.player1_active ? "ACTIU" : "INACTIU")
<< ", P2: " << ", P2: "
<< (match_config_.jugador2_actiu ? "ACTIU" : "INACTIU") << (match_config_.player2_active ? "ACTIU" : "INACTIU")
<< '\n'; << '\n';
// Consumir opciones (preparació per MODE_DEMO futur) // Consumir opciones (preparació per MODE_DEMO futur)
@@ -61,7 +61,7 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
// Basat en el codi Pascal original: line 376 // Basat en el codi Pascal original: line 376
std::srand(static_cast<unsigned>(std::time(nullptr))); std::srand(static_cast<unsigned>(std::time(nullptr)));
// Configurar el mundo físico con los límites de la zona de juego. // Configurar el mundo físico con los límites de la zone de juego.
physics_world_.clear(); physics_world_.clear();
physics_world_.setBounds(Defaults::Zones::PLAYAREA); physics_world_.setBounds(Defaults::Zones::PLAYAREA);
@@ -77,17 +77,17 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
}); });
// Fireworks generen una ripple gran al playfield (ona d'aigua centrada al burst). // Fireworks generen una ripple gran al playfield (ona d'aigua centrada al burst).
firework_manager_.setSpawnCallback([this](Vec2 origen) { firework_manager_.setSpawnCallback([this](Vec2 origin) {
playfield_.notifyExplosion(origen); playfield_.notifyExplosion(origin);
}); });
// Explosions properes a una paret també generen bump (falloff lineal amb la distància). // Explosions properes a una paret també generen bump (falloff lineal amb la distància).
debris_manager_.setExplosionCallback([this](Vec2 center) { debris_manager_.setExplosionCallback([this](Vec2 center) {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
const float DIST_LEFT = std::abs(center.x - zona.x); const float DIST_LEFT = std::abs(center.x - zone.x);
const float DIST_RIGHT = std::abs((zona.x + zona.w) - center.x); const float DIST_RIGHT = std::abs((zone.x + zone.w) - center.x);
const float DIST_TOP = std::abs(center.y - zona.y); const float DIST_TOP = std::abs(center.y - zone.y);
const float DIST_BOTTOM = std::abs((zona.y + zona.h) - center.y); const float DIST_BOTTOM = std::abs((zone.y + zone.h) - center.y);
const float MIN_DIST = std::min({DIST_LEFT, DIST_RIGHT, DIST_TOP, DIST_BOTTOM}); const float MIN_DIST = std::min({DIST_LEFT, DIST_RIGHT, DIST_TOP, DIST_BOTTOM});
if (MIN_DIST > Defaults::Border::EXPLOSION_FALLOFF_PX) { if (MIN_DIST > Defaults::Border::EXPLOSION_FALLOFF_PX) {
return; return;
@@ -130,9 +130,9 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
// Inicialitzar naves segons configuración (solo jugadors active) // Inicialitzar naves segons configuración (solo jugadors active)
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; bool player_active = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
if (jugador_actiu) { if (player_active) {
// Jugador active: init normalment // Jugador active: init normalment
Vec2 spawn_pos = getSpawnPoint(i); Vec2 spawn_pos = getSpawnPoint(i);
ships_[i].init(&spawn_pos, false); // No invulnerability at start ships_[i].init(&spawn_pos, false); // No invulnerability at start
@@ -248,11 +248,11 @@ void GameScene::stepPhysics(float delta_time) {
void GameScene::stepShootingInput() { void GameScene::stepShootingInput() {
auto* input = Input::get(); auto* input = Input::get();
if (match_config_.jugador1_actiu && if (match_config_.player1_active &&
input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) {
fireBullet(0); fireBullet(0);
} }
if (match_config_.jugador2_actiu && if (match_config_.player2_active &&
input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) { input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT)) {
fireBullet(1); fireBullet(1);
} }
@@ -267,16 +267,16 @@ void GameScene::stepMidGameJoin() {
// Solo se permite join si hay al menos un jugador vivo (no se puede // Solo se permite join si hay al menos un jugador vivo (no se puede
// hacer join en pantalla vacía). // hacer join en pantalla vacía).
const bool ALGU_VIU = const bool ALGU_VIU =
(match_config_.jugador1_actiu && hit_timer_per_player_[0] != Defaults::Game::HIT_TIMER_INACTIVE_PLAYER) || (match_config_.player1_active && hit_timer_per_player_[0] != Defaults::Game::HIT_TIMER_INACTIVE_PLAYER) ||
(match_config_.jugador2_actiu && hit_timer_per_player_[1] != Defaults::Game::HIT_TIMER_INACTIVE_PLAYER); (match_config_.player2_active && hit_timer_per_player_[1] != Defaults::Game::HIT_TIMER_INACTIVE_PLAYER);
if (!ALGU_VIU) { if (!ALGU_VIU) {
return; return;
} }
auto* input = Input::get(); auto* input = Input::get();
for (uint8_t pid = 0; pid < 2; pid++) { for (uint8_t pid = 0; pid < 2; pid++) {
const bool ACTIU = (pid == 0) ? match_config_.jugador1_actiu const bool ACTIU = (pid == 0) ? match_config_.player1_active
: match_config_.jugador2_actiu; : match_config_.player2_active;
const bool MUERTO_SIN_VIDAS = hit_timer_per_player_[pid] == Defaults::Game::HIT_TIMER_INACTIVE_PLAYER; const bool MUERTO_SIN_VIDAS = hit_timer_per_player_[pid] == Defaults::Game::HIT_TIMER_INACTIVE_PLAYER;
if (ACTIU && !MUERTO_SIN_VIDAS) { if (ACTIU && !MUERTO_SIN_VIDAS) {
continue; // jugador ya está jugando continue; // jugador ya está jugando
@@ -375,8 +375,8 @@ void GameScene::stepDeathSequence(float delta_time) {
// Sin vidas: marcar definitivamente muerto y comprobar transición a CONTINUE. // Sin vidas: marcar definitivamente muerto y comprobar transición a CONTINUE.
hit_timer_per_player_[i] = Defaults::Game::HIT_TIMER_INACTIVE_PLAYER; hit_timer_per_player_[i] = Defaults::Game::HIT_TIMER_INACTIVE_PLAYER;
const bool P1_DEAD = !match_config_.jugador1_actiu || lives_per_player_[0] <= 0; const bool P1_DEAD = !match_config_.player1_active || lives_per_player_[0] <= 0;
const bool P2_DEAD = !match_config_.jugador2_actiu || lives_per_player_[1] <= 0; const bool P2_DEAD = !match_config_.player2_active || lives_per_player_[1] <= 0;
if (P1_DEAD && P2_DEAD) { if (P1_DEAD && P2_DEAD) {
game_over_state_ = GameOverState::CONTINUE; game_over_state_ = GameOverState::CONTINUE;
continue_counter_ = Defaults::Game::CONTINUE_COUNT_START; continue_counter_ = Defaults::Game::CONTINUE_COUNT_START;
@@ -440,10 +440,10 @@ void GameScene::runStageInitHud(float delta_time) {
Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT, Defaults::Game::INIT_HUD_SHIP2_RATIO_INIT,
Defaults::Game::INIT_HUD_SHIP2_RATIO_END); Defaults::Game::INIT_HUD_SHIP2_RATIO_END);
if (match_config_.jugador1_actiu && SHIP1_P < 1.0F) { if (match_config_.player1_active && SHIP1_P < 1.0F) {
ships_[0].setCenter(Systems::InitHud::computeShipPosition(SHIP1_P, getSpawnPoint(0))); ships_[0].setCenter(Systems::InitHud::computeShipPosition(SHIP1_P, getSpawnPoint(0)));
} }
if (match_config_.jugador2_actiu && SHIP2_P < 1.0F) { if (match_config_.player2_active && SHIP2_P < 1.0F) {
ships_[1].setCenter(Systems::InitHud::computeShipPosition(SHIP2_P, getSpawnPoint(1))); ships_[1].setCenter(Systems::InitHud::computeShipPosition(SHIP2_P, getSpawnPoint(1)));
} }
} }
@@ -453,7 +453,7 @@ void GameScene::runStageLevelStart(float delta_time) {
// Ambas naves pueden moverse y disparar durante el intro. // Ambas naves pueden moverse y disparar durante el intro.
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; const bool ACTIU = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
if (ACTIU && hit_timer_per_player_[i] == 0.0F) { if (ACTIU && hit_timer_per_player_[i] == 0.0F) {
ships_[i].processInput(delta_time, i); ships_[i].processInput(delta_time, i);
ships_[i].update(delta_time); ships_[i].update(delta_time);
@@ -481,7 +481,7 @@ void GameScene::runStagePlaying(float delta_time) {
// Gameplay normal: ships activos + entidades + colisiones + efectos. // Gameplay normal: ships activos + entidades + colisiones + efectos.
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; const bool ACTIU = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
if (ACTIU && hit_timer_per_player_[i] == 0.0F) { if (ACTIU && hit_timer_per_player_[i] == 0.0F) {
ships_[i].processInput(delta_time, i); ships_[i].processInput(delta_time, i);
ships_[i].update(delta_time); ships_[i].update(delta_time);
@@ -491,7 +491,7 @@ void GameScene::runStagePlaying(float delta_time) {
enemy.update(delta_time); enemy.update(delta_time);
} }
// Col·lisions primer, després desactivació per fora-de-zona: així una bala que // Col·lisions primer, després desactivació per fora-de-zone: així una bala que
// el mateix frame xoca amb un enemic i alhora surt del PLAYAREA es compta com a // el mateix frame xoca amb un enemic i alhora surt del PLAYAREA es compta com a
// impacte abans no se la trenqui per sortir. // impacte abans no se la trenqui per sortir.
runCollisionDetections(); runCollisionDetections();
@@ -507,7 +507,7 @@ void GameScene::runStagePlaying(float delta_time) {
void GameScene::runStageLevelCompleted(float delta_time) { void GameScene::runStageLevelCompleted(float delta_time) {
stage_manager_->update(delta_time); stage_manager_->update(delta_time);
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
const bool ACTIU = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; const bool ACTIU = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
if (ACTIU && hit_timer_per_player_[i] == 0.0F) { if (ACTIU && hit_timer_per_player_[i] == 0.0F) {
ships_[i].processInput(delta_time, i); ships_[i].processInput(delta_time, i);
ships_[i].update(delta_time); ships_[i].update(delta_time);
@@ -580,8 +580,8 @@ void GameScene::drawBullets() const {
void GameScene::drawActiveShipsAlive() const { void GameScene::drawActiveShipsAlive() const {
for (uint8_t i = 0; i < 2; i++) { for (uint8_t i = 0; i < 2; i++) {
bool jugador_actiu = (i == 0) ? match_config_.jugador1_actiu : match_config_.jugador2_actiu; bool player_active = (i == 0) ? match_config_.player1_active : match_config_.player2_active;
if (jugador_actiu && hit_timer_per_player_[i] == 0.0F) { if (player_active && hit_timer_per_player_[i] == 0.0F) {
ships_[i].draw(); ships_[i].draw();
} }
} }
@@ -613,10 +613,10 @@ void GameScene::drawGameOverState() {
constexpr float SPACING = Defaults::Game::GameOverScreen::TEXT_SPACING; constexpr float SPACING = Defaults::Game::GameOverScreen::TEXT_SPACING;
const SDL_FRect& play_area = Defaults::Zones::PLAYAREA; const SDL_FRect& play_area = Defaults::Zones::PLAYAREA;
float centre_x = play_area.x + (play_area.w / 2.0F); float center_x = play_area.x + (play_area.w / 2.0F);
float centre_y = play_area.y + (play_area.h / 2.0F); float center_y = play_area.y + (play_area.h / 2.0F);
text_.renderCentered(GAME_OVER_TEXT, {.x = centre_x, .y = centre_y}, SCALE, SPACING); text_.renderCentered(GAME_OVER_TEXT, {.x = center_x, .y = center_y}, SCALE, SPACING);
drawScoreboard(); drawScoreboard();
} }
@@ -663,11 +663,11 @@ void GameScene::drawInitHudState() {
Systems::InitHud::drawScoreboardAnimated(text_, buildScoreboard(), score_progress); Systems::InitHud::drawScoreboardAnimated(text_, buildScoreboard(), score_progress);
} }
if (ship1_progress > 0.0F && match_config_.jugador1_actiu && ships_[0].isActive()) { if (ship1_progress > 0.0F && match_config_.player1_active && ships_[0].isActive()) {
ships_[0].draw(); ships_[0].draw();
} }
if (ship2_progress > 0.0F && match_config_.jugador2_actiu && ships_[1].isActive()) { if (ship2_progress > 0.0F && match_config_.player2_active && ships_[1].isActive()) {
ships_[1].draw(); ships_[1].draw();
} }
} }
@@ -769,20 +769,20 @@ void GameScene::drawScoreboard() {
const float SCALE = Defaults::Hud::SCOREBOARD_TEXT_SCALE; const float SCALE = Defaults::Hud::SCOREBOARD_TEXT_SCALE;
const float SPACING = Defaults::Hud::SCOREBOARD_TEXT_SPACING; const float SPACING = Defaults::Hud::SCOREBOARD_TEXT_SPACING;
// Calcular centro de la zona del marcador // Calcular centro de la zone del marcador
const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD; const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD;
float centre_x = scoreboard_zone.w / 2.0F; float center_x = scoreboard_zone.w / 2.0F;
float centre_y = scoreboard_zone.y + (scoreboard_zone.h / 2.0F); float center_y = scoreboard_zone.y + (scoreboard_zone.h / 2.0F);
// Renderizar centrat // Renderizar centrat
text_.renderCentered(text, {.x = centre_x, .y = centre_y}, SCALE, SPACING); text_.renderCentered(text, {.x = center_x, .y = center_y}, SCALE, SPACING);
} }
auto GameScene::buildScoreboard() const -> std::string { auto GameScene::buildScoreboard() const -> std::string {
// Puntuación P1 (6 dígits) - mostrar zeros si inactiu // Puntuación P1 (6 dígits) - mostrar zeros si inactiu
std::string score_p1; std::string score_p1;
std::string vides_p1; std::string vides_p1;
if (match_config_.jugador1_actiu) { if (match_config_.player1_active) {
score_p1 = std::to_string(score_per_player_[0]); score_p1 = std::to_string(score_per_player_[0]);
score_p1 = std::string(6 - std::min(6, static_cast<int>(score_p1.length())), '0') + score_p1; score_p1 = std::string(6 - std::min(6, static_cast<int>(score_p1.length())), '0') + score_p1;
vides_p1 = (lives_per_player_[0] < 10) vides_p1 = (lives_per_player_[0] < 10)
@@ -801,7 +801,7 @@ auto GameScene::buildScoreboard() const -> std::string {
// Puntuación P2 (6 dígits) - mostrar zeros si inactiu // Puntuación P2 (6 dígits) - mostrar zeros si inactiu
std::string score_p2; std::string score_p2;
std::string vides_p2; std::string vides_p2;
if (match_config_.jugador2_actiu) { if (match_config_.player2_active) {
score_p2 = std::to_string(score_per_player_[1]); score_p2 = std::to_string(score_per_player_[1]);
score_p2 = std::string(6 - std::min(6, static_cast<int>(score_p2.length())), '0') + score_p2; score_p2 = std::string(6 - std::min(6, static_cast<int>(score_p2.length())), '0') + score_p2;
vides_p2 = (lives_per_player_[1] < 10) vides_p2 = (lives_per_player_[1] < 10)
@@ -890,7 +890,7 @@ void GameScene::drawStageMessage(const std::string& message) {
// ======================================== // ========================================
auto GameScene::getSpawnPoint(uint8_t player_id) const -> Vec2 { auto GameScene::getSpawnPoint(uint8_t player_id) const -> Vec2 {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
float x_ratio; float x_ratio;
if (match_config_.isSinglePlayer()) { if (match_config_.isSinglePlayer()) {
@@ -904,8 +904,8 @@ auto GameScene::getSpawnPoint(uint8_t player_id) const -> Vec2 {
} }
return { return {
.x = zona.x + (zona.w * x_ratio), .x = zone.x + (zone.w * x_ratio),
.y = zona.y + (zona.h * Defaults::Game::SPAWN_Y_RATIO)}; .y = zone.y + (zone.h * Defaults::Game::SPAWN_Y_RATIO)};
} }
void GameScene::fireBullet(uint8_t player_id) { void GameScene::fireBullet(uint8_t player_id) {
@@ -950,10 +950,10 @@ void GameScene::drawContinue() {
float escala_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_SCALE; float escala_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_SCALE;
float y_ratio_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_Y_RATIO; float y_ratio_continue = Defaults::Game::ContinueScreen::CONTINUE_TEXT_Y_RATIO;
float centre_x = play_area.x + (play_area.w / 2.0F); float center_x = play_area.x + (play_area.w / 2.0F);
float centre_y_continue = play_area.y + (play_area.h * y_ratio_continue); float centre_y_continue = play_area.y + (play_area.h * y_ratio_continue);
text_.renderCentered(CONTINUE_TEXT, {.x = centre_x, .y = centre_y_continue}, escala_continue, SPACING); text_.renderCentered(CONTINUE_TEXT, {.x = center_x, .y = centre_y_continue}, escala_continue, SPACING);
// Countdown number (using constants) // Countdown number (using constants)
const std::string COUNTER_STR = std::to_string(continue_counter_); const std::string COUNTER_STR = std::to_string(continue_counter_);
@@ -962,7 +962,7 @@ void GameScene::drawContinue() {
float centre_y_counter = play_area.y + (play_area.h * y_ratio_counter); float centre_y_counter = play_area.y + (play_area.h * y_ratio_counter);
text_.renderCentered(COUNTER_STR, {.x = centre_x, .y = centre_y_counter}, escala_counter, SPACING); text_.renderCentered(COUNTER_STR, {.x = center_x, .y = centre_y_counter}, escala_counter, SPACING);
// "CONTINUES LEFT" (conditional + using constants) // "CONTINUES LEFT" (conditional + using constants)
if (!Defaults::Game::INFINITE_CONTINUES) { if (!Defaults::Game::INFINITE_CONTINUES) {
@@ -972,16 +972,16 @@ void GameScene::drawContinue() {
float centre_y_info = play_area.y + (play_area.h * y_ratio_info); float centre_y_info = play_area.y + (play_area.h * y_ratio_info);
text_.renderCentered(CONTINUES_TEXT, {.x = centre_x, .y = centre_y_info}, escala_info, SPACING); text_.renderCentered(CONTINUES_TEXT, {.x = center_x, .y = centre_y_info}, escala_info, SPACING);
} }
} }
void GameScene::joinPlayer(uint8_t player_id) { void GameScene::joinPlayer(uint8_t player_id) {
// Activate player // Activate player
if (player_id == 0) { if (player_id == 0) {
match_config_.jugador1_actiu = true; match_config_.player1_active = true;
} else { } else {
match_config_.jugador2_actiu = true; match_config_.player2_active = true;
} }
// Reset stats // Reset stats
+15 -15
View File
@@ -22,16 +22,16 @@ using Option = SceneContext::Option;
// Helper: calcular el progrés individual de una letter // Helper: calcular el progrés individual de una letter
// en función del progrés global (efecte seqüencial) // en función del progrés global (efecte seqüencial)
static auto computeLetterProgress(size_t letra_index, size_t num_letras, float global_progress, float threshold) -> float { static auto computeLetterProgress(size_t letter_index, size_t num_letters, float global_progress, float threshold) -> float {
if (num_letras == 0) { if (num_letters == 0) {
return 1.0F; return 1.0F;
} }
// Calcular time per letter // Calcular time per letter
float duration_per_letra = 1.0F / static_cast<float>(num_letras); float duration_per_letter = 1.0F / static_cast<float>(num_letters);
float step = threshold * duration_per_letra; float step = threshold * duration_per_letter;
float start = static_cast<float>(letra_index) * step; float start = static_cast<float>(letter_index) * step;
float end = start + duration_per_letra; float end = start + duration_per_letter;
// Interpolar progrés // Interpolar progrés
if (global_progress < start) { if (global_progress < start) {
@@ -179,7 +179,7 @@ void LogoScene::changeState(AnimationState nou_estat) {
} }
auto LogoScene::allLettersComplete() const -> bool { auto LogoScene::allLettersComplete() const -> bool {
// Cuando global_progress = 1.0, todas las lletres tenen letra_progress = 1.0 // Cuando global_progress = 1.0, todas las lletres tenen letter_progress = 1.0
return temps_current_state_ >= DURATION_ZOOM; return temps_current_state_ >= DURATION_ZOOM;
} }
@@ -231,14 +231,14 @@ void LogoScene::update(float delta_time) {
for (size_t i = 0; i < letters_.size() && i < sound_played_.size(); i++) { for (size_t i = 0; i < letters_.size() && i < sound_played_.size(); i++) {
if (!sound_played_[i]) { if (!sound_played_[i]) {
float letra_progress = computeLetterProgress( float letter_progress = computeLetterProgress(
i, i,
letters_.size(), letters_.size(),
global_progress, global_progress,
LETTER_THRESHOLD); LETTER_THRESHOLD);
// Reproduir so cuando la letter comença a aparèixer (progress > 0) // Reproduir so cuando la letter comença a aparèixer (progress > 0)
if (letra_progress > 0.0F) { if (letter_progress > 0.0F) {
Audio::get()->playSound(Defaults::Sound::LOGO, Audio::Group::GAME); Audio::get()->playSound(Defaults::Sound::LOGO, Audio::Group::GAME);
sound_played_[i] = true; sound_played_[i] = true;
} }
@@ -294,28 +294,28 @@ void LogoScene::draw() {
? std::min(temps_current_state_ / DURATION_ZOOM, 1.0F) ? std::min(temps_current_state_ / DURATION_ZOOM, 1.0F)
: 1.0F; // POST: mantenir al 100% : 1.0F; // POST: mantenir al 100%
const Vec2 ORIGEN_ZOOM = {.x = ORIGEN_ZOOM_X, .y = ORIGEN_ZOOM_Y}; const Vec2 ZOOM_ORIGIN = {.x = ZOOM_ORIGIN_X, .y = ZOOM_ORIGIN_Y};
for (size_t i = 0; i < letters_.size(); i++) { for (size_t i = 0; i < letters_.size(); i++) {
const auto& letter = letters_[i]; const auto& letter = letters_[i];
float letra_progress = computeLetterProgress( float letter_progress = computeLetterProgress(
i, i,
letters_.size(), letters_.size(),
global_progress, global_progress,
LETTER_THRESHOLD); LETTER_THRESHOLD);
if (letra_progress <= 0.0F) { if (letter_progress <= 0.0F) {
continue; continue;
} }
Vec2 pos_actual; Vec2 pos_actual;
pos_actual.x = pos_actual.x =
ORIGEN_ZOOM.x + ((letter.position.x - ORIGEN_ZOOM.x) * letra_progress); ZOOM_ORIGIN.x + ((letter.position.x - ZOOM_ORIGIN.x) * letter_progress);
pos_actual.y = pos_actual.y =
ORIGEN_ZOOM.y + ((letter.position.y - ORIGEN_ZOOM.y) * letra_progress); ZOOM_ORIGIN.y + ((letter.position.y - ZOOM_ORIGIN.y) * letter_progress);
float t = letra_progress; float t = letter_progress;
float ease_factor = 1.0F - ((1.0F - t) * (1.0F - t)); float ease_factor = 1.0F - ((1.0F - t) * (1.0F - t));
float current_scale = float current_scale =
INITIAL_SCALE + ((FINAL_SCALE - INITIAL_SCALE) * ease_factor); INITIAL_SCALE + ((FINAL_SCALE - INITIAL_SCALE) * ease_factor);
+2 -2
View File
@@ -80,8 +80,8 @@ class LogoScene final : public Scene {
// Constants de animación seqüencial // Constants de animación seqüencial
static constexpr float LETTER_THRESHOLD = 0.6F; // Umbral per activar següent letter (0.0-1.0) static constexpr float LETTER_THRESHOLD = 0.6F; // Umbral per activar següent letter (0.0-1.0)
static constexpr float ORIGEN_ZOOM_X = Defaults::Game::WIDTH * 0.5F; // Vec2 inicial X del zoom static constexpr float ZOOM_ORIGIN_X = Defaults::Game::WIDTH * 0.5F; // Vec2 inicial X del zoom
static constexpr float ORIGEN_ZOOM_Y = Defaults::Game::HEIGHT * 0.4F; // Vec2 inicial Y del zoom static constexpr float ZOOM_ORIGIN_Y = Defaults::Game::HEIGHT * 0.4F; // Vec2 inicial Y del zoom
// Métodos privats // Métodos privats
void initLetters(); void initLetters();
+12 -12
View File
@@ -36,8 +36,8 @@ TitleScene::TitleScene(SDLManager& sdl, SceneContext& context)
text_(sdl.getRenderer()) { text_(sdl.getRenderer()) {
std::cout << "SceneType Titol: Inicialitzant...\n"; std::cout << "SceneType Titol: Inicialitzant...\n";
match_config_.jugador1_actiu = false; match_config_.player1_active = false;
match_config_.jugador2_actiu = false; match_config_.player2_active = false;
match_config_.mode = GameConfig::Mode::NORMAL; match_config_.mode = GameConfig::Mode::NORMAL;
auto option = context_.consumeOption(); auto option = context_.consumeOption();
@@ -404,8 +404,8 @@ void TitleScene::updatePlayerJoinPhaseState(float delta_time) {
temps_acumulat_ += delta_time; temps_acumulat_ += delta_time;
updateLogoAnimation(delta_time); updateLogoAnimation(delta_time);
const bool P1_ABANS = match_config_.jugador1_actiu; const bool P1_ABANS = match_config_.player1_active;
const bool P2_ABANS = match_config_.jugador2_actiu; const bool P2_ABANS = match_config_.player2_active;
if (checkStartGameButtonPressed()) { if (checkStartGameButtonPressed()) {
context_.setMatchConfig(match_config_); context_.setMatchConfig(match_config_);
@@ -466,8 +466,8 @@ void TitleScene::handleStartInput() {
if (!press_start_visible_) { if (!press_start_visible_) {
return; return;
} }
const bool P1_ABANS = match_config_.jugador1_actiu; const bool P1_ABANS = match_config_.player1_active;
const bool P2_ABANS = match_config_.jugador2_actiu; const bool P2_ABANS = match_config_.player2_active;
if (!checkStartGameButtonPressed()) { if (!checkStartGameButtonPressed()) {
return; return;
@@ -492,11 +492,11 @@ void TitleScene::triggerExitForJoinedPlayers(bool p1_was_active, bool p2_was_act
if (ship_animator_ == nullptr) { if (ship_animator_ == nullptr) {
return; return;
} }
if (match_config_.jugador1_actiu && !p1_was_active) { if (match_config_.player1_active && !p1_was_active) {
ship_animator_->triggerExitAnimationForPlayer(1); ship_animator_->triggerExitAnimationForPlayer(1);
std::cout << "[TitleScene] P1 " << log_prefix << "ship exiting\n"; std::cout << "[TitleScene] P1 " << log_prefix << "ship exiting\n";
} }
if (match_config_.jugador2_actiu && !p2_was_active) { if (match_config_.player2_active && !p2_was_active) {
ship_animator_->triggerExitAnimationForPlayer(2); ship_animator_->triggerExitAnimationForPlayer(2);
std::cout << "[TitleScene] P2 " << log_prefix << "ship exiting\n"; std::cout << "[TitleScene] P2 " << log_prefix << "ship exiting\n";
} }
@@ -622,14 +622,14 @@ auto TitleScene::checkStartGameButtonPressed() -> bool {
bool any_pressed = false; bool any_pressed = false;
for (auto action : START_GAME_BUTTONS) { for (auto action : START_GAME_BUTTONS) {
if (input->checkActionPlayer1(action, Input::DO_NOT_ALLOW_REPEAT)) { if (input->checkActionPlayer1(action, Input::DO_NOT_ALLOW_REPEAT)) {
if (!match_config_.jugador1_actiu) { if (!match_config_.player1_active) {
match_config_.jugador1_actiu = true; match_config_.player1_active = true;
any_pressed = true; any_pressed = true;
} }
} }
if (input->checkActionPlayer2(action, Input::DO_NOT_ALLOW_REPEAT)) { if (input->checkActionPlayer2(action, Input::DO_NOT_ALLOW_REPEAT)) {
if (!match_config_.jugador2_actiu) { if (!match_config_.player2_active) {
match_config_.jugador2_actiu = true; match_config_.player2_active = true;
any_pressed = true; any_pressed = true;
} }
} }
+2 -2
View File
@@ -262,8 +262,8 @@ namespace Systems::Collision {
continue; continue;
} }
const bool JUGADOR_ACTIU = (player_id == 0) const bool JUGADOR_ACTIU = (player_id == 0)
? ctx.match_config.jugador1_actiu ? ctx.match_config.player1_active
: ctx.match_config.jugador2_actiu; : ctx.match_config.player2_active;
if (!JUGADOR_ACTIU) { if (!JUGADOR_ACTIU) {
continue; continue;
} }
+79 -79
View File
@@ -11,99 +11,99 @@
#include "game/scenes/game_scene.hpp" // GameOverState (definición completa) #include "game/scenes/game_scene.hpp" // GameOverState (definición completa)
namespace Systems::ContinueScreen { namespace Systems::ContinueScreen {
namespace { namespace {
// Si el countdown ha bajado de 0, transiciona a GAME_OVER con su timer. // Si el countdown ha bajado de 0, transiciona a GAME_OVER con su timer.
void checkAndApplyTimeout(Context& ctx) { void checkAndApplyTimeout(Context& ctx) {
if (ctx.counter < 0) { if (ctx.counter < 0) {
ctx.state = GameOverState::GAME_OVER; ctx.state = GameOverState::GAME_OVER;
ctx.game_over_timer = Defaults::Game::GAME_OVER_DURATION; ctx.game_over_timer = Defaults::Game::GAME_OVER_DURATION;
} }
} }
void revivePlayer(Context& ctx, uint8_t player_id) { void revivePlayer(Context& ctx, uint8_t player_id) {
ctx.score_per_player[player_id] = 0; ctx.score_per_player[player_id] = 0;
ctx.lives_per_player[player_id] = Defaults::Game::STARTING_LIVES; ctx.lives_per_player[player_id] = Defaults::Game::STARTING_LIVES;
ctx.hit_timer_per_player[player_id] = 0.0F; ctx.hit_timer_per_player[player_id] = 0.0F;
if (player_id == 0) { if (player_id == 0) {
ctx.match_config.jugador1_actiu = true; ctx.match_config.player1_active = true;
} else { } else {
ctx.match_config.jugador2_actiu = true; ctx.match_config.player2_active = true;
} }
const Vec2 SPAWN = ctx.get_spawn_point(player_id); const Vec2 SPAWN = ctx.get_spawn_point(player_id);
ctx.ships[player_id].init(&SPAWN, /*activar_invulnerabilitat=*/true); ctx.ships[player_id].init(&SPAWN, /*activar_invulnerabilitat=*/true);
} }
} // namespace } // namespace
void update(Context& ctx, float delta_time) { void update(Context& ctx, float delta_time) {
ctx.tick_timer -= delta_time; ctx.tick_timer -= delta_time;
if (ctx.tick_timer > 0.0F) { if (ctx.tick_timer > 0.0F) {
return;
}
ctx.counter--;
ctx.tick_timer = Defaults::Game::CONTINUE_TICK_DURATION;
checkAndApplyTimeout(ctx);
// Solo pita el tick si seguimos en CONTINUE (no transitamos a GAME_OVER)
if (ctx.state == GameOverState::CONTINUE) {
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
}
}
void processInput(Context& ctx) {
auto* input = Input::get();
const bool P1_START = input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
const bool P2_START = input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
if (P1_START || P2_START) {
// ¿Quedan continues?
if (!Defaults::Game::INFINITE_CONTINUES &&
ctx.continues_used >= Defaults::Game::MAX_CONTINUES) {
ctx.state = GameOverState::GAME_OVER;
ctx.game_over_timer = Defaults::Game::GAME_OVER_DURATION;
return; return;
} }
if (!Defaults::Game::INFINITE_CONTINUES) {
ctx.continues_used++;
}
const uint8_t PRIMARY = P1_START ? 0 : 1;
revivePlayer(ctx, PRIMARY);
// Si ambos pulsan START, revivimos a los dos.
if (P1_START && P2_START) {
revivePlayer(ctx, 1);
}
// Reanudar partida.
ctx.state = GameOverState::NONE;
ctx.counter = 0;
ctx.tick_timer = 0.0F;
Audio::get()->playSound(Defaults::Sound::START, Audio::Group::GAME);
return;
}
// THRUST/SHOOT acelera el countdown manualmente.
const bool ACCEL = input->checkActionPlayer1(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer2(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
if (ACCEL) {
ctx.counter--; ctx.counter--;
ctx.tick_timer = Defaults::Game::CONTINUE_TICK_DURATION;
checkAndApplyTimeout(ctx); checkAndApplyTimeout(ctx);
// Solo pita el tick si seguimos en CONTINUE (no transitamos a GAME_OVER)
if (ctx.state == GameOverState::CONTINUE) { if (ctx.state == GameOverState::CONTINUE) {
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME); Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
} }
ctx.tick_timer = Defaults::Game::CONTINUE_TICK_DURATION;
} }
}
void processInput(Context& ctx) {
auto* input = Input::get();
const bool P1_START = input->checkActionPlayer1(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
const bool P2_START = input->checkActionPlayer2(InputAction::START, Input::DO_NOT_ALLOW_REPEAT);
if (P1_START || P2_START) {
// ¿Quedan continues?
if (!Defaults::Game::INFINITE_CONTINUES &&
ctx.continues_used >= Defaults::Game::MAX_CONTINUES) {
ctx.state = GameOverState::GAME_OVER;
ctx.game_over_timer = Defaults::Game::GAME_OVER_DURATION;
return;
}
if (!Defaults::Game::INFINITE_CONTINUES) {
ctx.continues_used++;
}
const uint8_t PRIMARY = P1_START ? 0 : 1;
revivePlayer(ctx, PRIMARY);
// Si ambos pulsan START, revivimos a los dos.
if (P1_START && P2_START) {
revivePlayer(ctx, 1);
}
// Reanudar partida.
ctx.state = GameOverState::NONE;
ctx.counter = 0;
ctx.tick_timer = 0.0F;
Audio::get()->playSound(Defaults::Sound::START, Audio::Group::GAME);
return;
}
// THRUST/SHOOT acelera el countdown manualmente.
const bool ACCEL = input->checkActionPlayer1(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer2(InputAction::THRUST, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer1(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT) ||
input->checkActionPlayer2(InputAction::SHOOT, Input::DO_NOT_ALLOW_REPEAT);
if (ACCEL) {
ctx.counter--;
checkAndApplyTimeout(ctx);
if (ctx.state == GameOverState::CONTINUE) {
Audio::get()->playSound(Defaults::Sound::CONTINUE, Audio::Group::GAME);
}
ctx.tick_timer = Defaults::Game::CONTINUE_TICK_DURATION;
}
}
} // namespace Systems::ContinueScreen } // namespace Systems::ContinueScreen
+1 -1
View File
@@ -31,7 +31,7 @@ namespace Systems::InitHud {
auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 { auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
const float EASED = Easing::easeOutQuad(progress); const float EASED = Easing::easeOutQuad(progress);
const SDL_FRect& zone = Defaults::Zones::PLAYAREA; const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
// Y inicial: bajo la zona de juego (sale desde fuera). // Y inicial: bajo la zone de juego (sale desde fuera).
const float Y_INI = zone.y + zone.h + Defaults::Hud::InitAnim::SHIP_SPAWN_Y_OFFSET; const float Y_INI = zone.y + zone.h + Defaults::Hud::InitAnim::SHIP_SPAWN_Y_OFFSET;
const float Y_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED); const float Y_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED);
return Vec2{.x = final_position.x, .y = Y_ANIM}; return Vec2{.x = final_position.x, .y = Y_ANIM};
+22 -22
View File
@@ -4,7 +4,7 @@
// Cubre la animación INIT_HUD del comienzo de cada partida/stage: // Cubre la animación INIT_HUD del comienzo de cada partida/stage:
// 1. Crecimiento de los marcos del PLAYAREA con efecto pincel en 3 fases. // 1. Crecimiento de los marcos del PLAYAREA con efecto pincel en 3 fases.
// 2. Marcador subiendo desde abajo. // 2. Marcador subiendo desde abajo.
// 3. Naves entrando desde la zona inferior hacia su spawn. // 3. Naves entrando desde la zone inferior hacia su spawn.
// //
// Todas las funciones son puras (sin estado interno propio). GameScene aporta // Todas las funciones son puras (sin estado interno propio). GameScene aporta
// el contexto que necesitan: posiciones finales, texto del scoreboard y el // el contexto que necesitan: posiciones finales, texto del scoreboard y el
@@ -21,29 +21,29 @@
namespace Systems::InitHud { namespace Systems::InitHud {
// Convierte un progreso global 0..1 al sub-progreso de un elemento que solo // Convierte un progreso global 0..1 al sub-progreso de un elemento que solo
// se anima en la ventana [ratio_init, ratio_end]. // se anima en la ventana [ratio_init, ratio_end].
// < ratio_init → 0.0 (no empezó) // < ratio_init → 0.0 (no empezó)
// > ratio_end → 1.0 (terminó) // > ratio_end → 1.0 (terminó)
// en rango → interpolación lineal 0..1 // en rango → interpolación lineal 0..1
[[nodiscard]] auto computeRangeProgress(float global_progress, [[nodiscard]] auto computeRangeProgress(float global_progress,
float ratio_init, float ratio_init,
float ratio_end) -> float; float ratio_end) -> float;
// Calcula posición Y animada de una nave durante INIT_HUD. La nave sube // Calcula posición Y animada de una nave durante INIT_HUD. La nave sube
// desde 50 px bajo el PLAYAREA hasta `final_position` con easing. // desde 50 px bajo el PLAYAREA hasta `final_position` con easing.
[[nodiscard]] auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2; [[nodiscard]] auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2;
// Dibuja los 4 lados del PLAYAREA con efecto pincel en 3 fases: // Dibuja los 4 lados del PLAYAREA con efecto pincel en 3 fases:
// 0..33% → línea superior crece desde el centro hacia los lados. // 0..33% → línea superior crece desde el centro hacia los lados.
// 33..66% → líneas verticales bajan por los laterales. // 33..66% → líneas verticales bajan por los laterales.
// 66..100% → línea inferior crece desde los lados hacia el centro. // 66..100% → línea inferior crece desde los lados hacia el centro.
void drawBordersAnimated(Rendering::Renderer* renderer, float progress); void drawBordersAnimated(Rendering::Renderer* renderer, float progress);
// Dibuja el scoreboard centrado, subiendo desde fuera de la pantalla // Dibuja el scoreboard centrado, subiendo desde fuera de la pantalla
// hasta su posición final con easing. // hasta su posición final con easing.
void drawScoreboardAnimated(const Graphics::VectorText& text, void drawScoreboardAnimated(const Graphics::VectorText& text,
const std::string& scoreboard_text, const std::string& scoreboard_text,
float progress); float progress);
} // namespace Systems::InitHud } // namespace Systems::InitHud