refactor(defaults): centralitza init hud, tips, hit timer, line thickness i debug overlay

This commit is contained in:
2026-05-21 09:45:55 +02:00
parent 08100f60e8
commit 7139dea7f6
8 changed files with 111 additions and 75 deletions
+7 -3
View File
@@ -10,9 +10,13 @@ namespace Defaults::Game {
constexpr int HEIGHT = 720;
// Regles de partida
constexpr int STARTING_LIVES = 3; // Initial lives
constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation
constexpr float GAME_OVER_DURATION = 5.0F; // Seconds to display game over
constexpr int STARTING_LIVES = 3; // Initial lives
constexpr float DEATH_DURATION = 3.0F; // Seconds of death animation
constexpr float GAME_OVER_DURATION = 5.0F; // Seconds to display game over
// Valores centinela del temporitzador de mort per-jugador.
constexpr float HIT_TIMER_INACTIVE_PLAYER = 999.0F; // Jugador permanentment inactiu
constexpr float HIT_TIMER_TRIGGER_DEATH = 0.001F; // Trigger inicial post-impacte (>0 sense disparar regla)
constexpr float COLLISION_SHIP_ENEMY_AMPLIFIER = 0.80F; // 80% hitbox (generous)
constexpr float COLLISION_BULLET_ENEMY_AMPLIFIER = 1.15F; // 115% hitbox (generous)
+28
View File
@@ -10,4 +10,32 @@ namespace Defaults::Hud {
constexpr float SCOREBOARD_TEXT_SCALE = 0.85F;
constexpr float SCOREBOARD_TEXT_SPACING = 0.0F;
// Animación de entrada del HUD (init_hud_animator).
namespace InitAnim {
// Spawn vertical de la nave: 50 px bajo la PLAYAREA (sale desde fuera).
constexpr float SHIP_SPAWN_Y_OFFSET = 50.0F;
// Bordes: ratios de las tres fases (top → laterales → bottom).
constexpr float BORDER_PHASE_1_END = 0.33F; // Fin de la fase top
constexpr float BORDER_PHASE_2_END = 0.66F; // Fin de la fase laterales
} // namespace InitAnim
// Indicadores ("tips") sobre los enemigos enganchados a la nave.
// Offset local al frame de la nave (apunta hacia delante, eje Y negativo).
namespace Tips {
constexpr float LOCAL_X = 0.0F;
constexpr float LOCAL_Y = -12.0F;
} // namespace Tips
// Overlay de debug (FPS, métriques) en coordenades lògiques (1280×720).
namespace DebugOverlay {
constexpr float X = 12.0F;
constexpr float Y_FPS = 12.0F;
constexpr float LINE_HEIGHT = 18.0F; // separació entre línies (scale 0.4 → ~16 px alt)
constexpr float TEXT_SCALE = 0.4F;
constexpr float TEXT_SPACING = 2.0F;
constexpr float BRIGHTNESS = 1.0F;
constexpr float FPS_UPDATE_INTERVAL = 0.5F; // Cadencia d'actualització del FPS visible
} // namespace DebugOverlay
} // namespace Defaults::Hud
+3
View File
@@ -26,6 +26,9 @@ namespace Defaults::Physics {
constexpr float FACTOR_HERENCIA_MAX = 1.0F; // Màxim 100% del drotacio heredat
constexpr float FRICCIO_ANGULAR = 0.5F; // Desacceleració angular (rad/s²)
// Velocity heredada de la nau a l'explosió (80% del feel original).
constexpr float SHIP_VELOCITY_INHERITANCE = 0.8F;
// Angular velocity sin for trajectory inheritance
// Excess above this threshold is converted to tangential linear velocity
// Prevents "vortex trap" problem with high-rotation enemies
+4
View File
@@ -11,6 +11,10 @@ namespace Defaults::Rendering {
constexpr int VSYNC_DEFAULT = 1; // 0=disabled, 1=enabled
constexpr int ANTIALIAS_DEFAULT = 1; // 0=disabled, 1=enabled (AA geomètric a les línies)
// Grosor global per defecte de les línies. 1.5 dóna línia visible i crujent;
// 1.0 es veu massa fi en pantalles grans. Configurable via setLineThickness.
constexpr float LINE_THICKNESS_DEFAULT = 1.5F;
// Resolució del render target offscreen. El tamany lògic del joc roman a
// 1280×720 (coordenades dels objectes); aquesta és la resolució física a
// la qual es rasteritzen les línies abans de la composició final.
+42 -38
View File
@@ -3,52 +3,56 @@
#include "core/rendering/line_renderer.hpp"
#include "core/defaults.hpp"
namespace Rendering {
// Color global compartido para líneas sin paleta propia (HUD, debug, texto
// genérico). Equivale al "color máximo" de la antigua oscilación CPU: verde
// fósforo CRT. El pulso de brillo lo aplica ahora el shader de postpro.
SDL_Color g_current_line_color = {100, 255, 100, 255};
// Color global compartido para líneas sin paleta propia (HUD, debug, texto
// genérico). Equivale al "color máximo" de la antigua oscilación CPU: verde
// fósforo CRT. El pulso de brillo lo aplica ahora el shader de postpro.
SDL_Color g_current_line_color = {100, 255, 100, 255};
// Grosor global por defecto. Configurable via setLineThickness.
// 1.5 da una línea visible y crujiente; 1.0 se ve demasiado fino en pantallas grandes.
float g_current_line_thickness = 1.5F;
// Grosor global por defecto. Configurable via setLineThickness.
float g_current_line_thickness = Defaults::Rendering::LINE_THICKNESS_DEFAULT;
void linea(Renderer* renderer,
int x1, int y1, int x2, int y2,
float brightness,
float thickness,
SDL_Color color) {
if (renderer == nullptr) {
return;
void linea(Renderer* renderer,
int x1,
int y1,
int x2,
int y2,
float brightness,
float thickness,
SDL_Color color) {
if (renderer == nullptr) {
return;
}
// Coords lógicas (1280×720). El shader hace el mapeo a NDC; el viewport
// del SDLManager hace el letterbox a píxeles físicos.
const auto FX1 = static_cast<float>(x1);
const auto FY1 = static_cast<float>(y1);
const auto FX2 = static_cast<float>(x2);
const auto FY2 = static_cast<float>(y2);
// color.alpha==0 → usar color global (verde fósforo). alpha>0 → color directo.
const SDL_Color SOURCE = (color.a > 0) ? color : g_current_line_color;
const float R = (static_cast<float>(SOURCE.r) * brightness) / 255.0F;
const float G = (static_cast<float>(SOURCE.g) * brightness) / 255.0F;
const float B = (static_cast<float>(SOURCE.b) * brightness) / 255.0F;
const float W = (thickness > 0.0F) ? thickness : g_current_line_thickness;
renderer->pushLine(FX1, FY1, FX2, FY2, W, R, G, B, 1.0F);
}
// Coords lógicas (1280×720). El shader hace el mapeo a NDC; el viewport
// del SDLManager hace el letterbox a píxeles físicos.
const auto FX1 = static_cast<float>(x1);
const auto FY1 = static_cast<float>(y1);
const auto FX2 = static_cast<float>(x2);
const auto FY2 = static_cast<float>(y2);
void setLineColor(SDL_Color color) { g_current_line_color = color; }
// color.alpha==0 → usar color global (verde fósforo). alpha>0 → color directo.
const SDL_Color SOURCE = (color.a > 0) ? color : g_current_line_color;
const float R = (static_cast<float>(SOURCE.r) * brightness) / 255.0F;
const float G = (static_cast<float>(SOURCE.g) * brightness) / 255.0F;
const float B = (static_cast<float>(SOURCE.b) * brightness) / 255.0F;
const float W = (thickness > 0.0F) ? thickness : g_current_line_thickness;
renderer->pushLine(FX1, FY1, FX2, FY2, W, R, G, B, 1.0F);
}
void setLineColor(SDL_Color color) { g_current_line_color = color; }
void setLineThickness(float thickness) {
if (thickness > 0.0F) {
g_current_line_thickness = thickness;
void setLineThickness(float thickness) {
if (thickness > 0.0F) {
g_current_line_thickness = thickness;
}
}
}
auto getLineThickness() -> float { return g_current_line_thickness; }
auto getLineThickness() -> float { return g_current_line_thickness; }
} // namespace Rendering
+15 -23
View File
@@ -4,21 +4,13 @@
#include <string>
#include "core/defaults.hpp"
#include "core/types.hpp"
namespace System {
namespace {
// Posición y tamaño del overlay en coordenadas lógicas (1280×720).
constexpr float OVERLAY_X = 12.0F;
constexpr float OVERLAY_Y_FPS = 12.0F;
constexpr float OVERLAY_LINE_HEIGHT = 18.0F; // separación entre líneas (scale 0.4 → ~16 px alto)
constexpr float OVERLAY_SCALE = 0.4F;
constexpr float OVERLAY_SPACING = 2.0F;
constexpr float OVERLAY_BRIGHTNESS = 1.0F;
// Cadencia de actualización del valor de FPS mostrado.
constexpr float FPS_UPDATE_INTERVAL = 0.5F;
namespace Cfg = Defaults::Hud::DebugOverlay;
} // namespace
DebugOverlay::DebugOverlay(Rendering::Renderer* renderer,
@@ -30,7 +22,7 @@ namespace System {
fps_accumulator_ += delta_time;
fps_frame_count_++;
if (fps_accumulator_ >= FPS_UPDATE_INTERVAL) {
if (fps_accumulator_ >= Cfg::FPS_UPDATE_INTERVAL) {
fps_display_ = static_cast<int>(fps_frame_count_ / fps_accumulator_);
fps_frame_count_ = 0;
fps_accumulator_ = 0.0F;
@@ -47,20 +39,20 @@ namespace System {
const std::string AA_TEXT = std::string("AA: ") + (rendering_cfg_->antialias == 1 ? "ON" : "OFF");
text_.render(FPS_TEXT,
Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS},
OVERLAY_SCALE,
OVERLAY_SPACING,
OVERLAY_BRIGHTNESS);
Vec2{.x = Cfg::X, .y = Cfg::Y_FPS},
Cfg::TEXT_SCALE,
Cfg::TEXT_SPACING,
Cfg::BRIGHTNESS);
text_.render(VSYNC_TEXT,
Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS + OVERLAY_LINE_HEIGHT},
OVERLAY_SCALE,
OVERLAY_SPACING,
OVERLAY_BRIGHTNESS);
Vec2{.x = Cfg::X, .y = Cfg::Y_FPS + Cfg::LINE_HEIGHT},
Cfg::TEXT_SCALE,
Cfg::TEXT_SPACING,
Cfg::BRIGHTNESS);
text_.render(AA_TEXT,
Vec2{.x = OVERLAY_X, .y = OVERLAY_Y_FPS + (2.0F * OVERLAY_LINE_HEIGHT)},
OVERLAY_SCALE,
OVERLAY_SPACING,
OVERLAY_BRIGHTNESS);
Vec2{.x = Cfg::X, .y = Cfg::Y_FPS + (2.0F * Cfg::LINE_HEIGHT)},
Cfg::TEXT_SCALE,
Cfg::TEXT_SPACING,
Cfg::BRIGHTNESS);
}
} // namespace System
+8 -7
View File
@@ -107,8 +107,8 @@ GameScene::GameScene(SDLManager& sdl, SceneContext& context)
} else {
// Jugador inactiu: marcar como a mort permanent
ships_[i].markHit();
hit_timer_per_player_[i] = 999.0F; // Valor sentinella (permanent inactiu)
lives_per_player_[i] = 0; // Sin vides
hit_timer_per_player_[i] = Defaults::Game::HIT_TIMER_INACTIVE_PLAYER;
lives_per_player_[i] = 0; // Sin vides
std::cout << "[GameScene] Jugador " << (i + 1) << " inactiu\n";
}
}
@@ -628,8 +628,9 @@ void GameScene::tocado(uint8_t player_id) {
const Vec2& ship_pos = ships_[player_id].getCenter();
float ship_angle = ships_[player_id].getAngle();
Vec2 vel_nau = ships_[player_id].getVelocityVector();
// Reduir a 80% la velocity heretada per la ship (més realista)
Vec2 vel_nau_80 = {.x = vel_nau.x * 0.8F, .y = vel_nau.y * 0.8F};
// Reduir la velocity heretada per la ship segons defaults (més realista)
constexpr float INHERIT = Defaults::Physics::Debris::SHIP_VELOCITY_INHERITANCE;
Vec2 vel_nau_80 = {.x = vel_nau.x * INHERIT, .y = vel_nau.y * INHERIT};
debris_manager_.explode(
ships_[player_id].getShape(), // Ship shape (3 lines)
@@ -646,7 +647,7 @@ void GameScene::tocado(uint8_t player_id) {
);
// Start death timer (non-zero to avoid re-triggering)
hit_timer_per_player_[player_id] = 0.001F;
hit_timer_per_player_[player_id] = Defaults::Game::HIT_TIMER_TRIGGER_DEATH;
}
// Phase 2 is automatic (debris updates in update())
// Phase 3 is handled in update() when hit_timer_per_player_ >= DEATH_DURATION
@@ -828,8 +829,8 @@ void GameScene::fireBullet(uint8_t player_id) {
const Vec2& ship_centre = ships_[player_id].getCenter();
float ship_angle = ships_[player_id].getAngle();
constexpr float LOCAL_TIP_X = 0.0F;
constexpr float LOCAL_TIP_Y = -12.0F;
constexpr float LOCAL_TIP_X = Defaults::Hud::Tips::LOCAL_X;
constexpr float LOCAL_TIP_Y = Defaults::Hud::Tips::LOCAL_Y;
float cos_a = std::cos(ship_angle);
float sin_a = std::sin(ship_angle);
float tip_x = (LOCAL_TIP_X * cos_a) - (LOCAL_TIP_Y * sin_a) + ship_centre.x;
+4 -4
View File
@@ -31,8 +31,8 @@ namespace Systems::InitHud {
auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
const float EASED = Easing::easeOutQuad(progress);
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
// Y inicial: 50 px bajo la zona de juego.
const float Y_INI = zone.y + zone.h + 50.0F;
// Y inicial: bajo la zona de juego (sale desde fuera).
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);
return Vec2{.x = final_position.x, .y = Y_ANIM};
}
@@ -47,8 +47,8 @@ namespace Systems::InitHud {
const int Y2 = static_cast<int>(zone.y + zone.h);
const int CX = (X1 + X2) / 2;
constexpr float PHASE_1_END = 0.33F;
constexpr float PHASE_2_END = 0.66F;
constexpr float PHASE_1_END = Defaults::Hud::InitAnim::BORDER_PHASE_1_END;
constexpr float PHASE_2_END = Defaults::Hud::InitAnim::BORDER_PHASE_2_END;
// Fase 1: línea superior crece desde el centro hacia los lados.
if (EASED > 0.0F) {