tweak(hud): vides com a slots fixos (NUM_SLOTS = MAX_VIDES-1) que s'encenen/atenuen
This commit is contained in:
@@ -30,21 +30,9 @@ namespace Defaults::Hud {
|
||||
constexpr SDL_Color LEVEL_DIM = {.r = 29, .g = 107, .b = 44, .a = 255}; // #1D6B2C
|
||||
} // namespace Colors
|
||||
|
||||
// Vides representades com a icones de la nau (reutilitza la shape de la nau
|
||||
// escalada, no un número). Mides derivades de l'alçada del marcador
|
||||
// (Defaults::Zones::SCOREBOARD_BOTTOM_H) per encaixar-hi sempre.
|
||||
namespace Lives {
|
||||
constexpr float ICON_HEIGHT_RATIO = 0.45F; // alçada de la icona com a fracció de l'alçada del marcador
|
||||
constexpr float ICON_SPACING_FACTOR = 1.35F; // separació centre-a-centre = alçada_icona × factor
|
||||
constexpr int MAX_ICONS = 5; // límit d'icones dibuixades (acota l'ample del bloc)
|
||||
} // namespace Lives
|
||||
|
||||
// Disposició del marcador: bloc P1 ancorat a l'esquerra, bloc P2 a la dreta
|
||||
// (mateix ordre intern "punts vides", no mirrored) i nivell centrat. Els
|
||||
// blocs s'alineen amb les verticals del PLAYAREA.
|
||||
namespace Layout {
|
||||
constexpr float BLOCK_INNER_GAP = 24.0F; // separació punts↔vides dins d'un bloc (px lògics)
|
||||
} // namespace Layout
|
||||
// Les vides es dibuixen com a slots fixos de naus en miniatura (NUM_SLOTS =
|
||||
// MAX_VIDES − 1). Mida i pas dels slots es deriven de la mètrica del glif del
|
||||
// dígit a init_hud_animator, no de constants soltes.
|
||||
|
||||
// Animación de entrada del HUD (init_hud_animator).
|
||||
namespace InitAnim {
|
||||
|
||||
@@ -81,49 +81,57 @@ namespace Systems::InitHud {
|
||||
|
||||
namespace {
|
||||
|
||||
// Alçada de la icona de vida (px lògics) derivada de l'alçada del marcador.
|
||||
auto lifeIconHeight() -> float {
|
||||
return Defaults::Hud::Lives::ICON_HEIGHT_RATIO * Defaults::Zones::SCOREBOARD_BOTTOM_H;
|
||||
// Nombre de slots de vides: una nau menys que el màxim (la nau en joc
|
||||
// no es dibuixa; els slots són repuestos). Deriva de MAX_VIDES.
|
||||
constexpr int NUM_SLOTS = Defaults::Game::MAX_VIDES - 1;
|
||||
|
||||
// Pas d'un dígit (amplada + tracking, escalat): és la diferència entre
|
||||
// l'ample de dos caràcters i el d'un. Marca el ritme de tot el bloc.
|
||||
auto digitPitch(float scale, float spacing) -> float {
|
||||
return Graphics::VectorText::getTextWidth("00", scale, spacing) -
|
||||
Graphics::VectorText::getTextWidth("0", scale, spacing);
|
||||
}
|
||||
|
||||
// Nombre d'icones de vida a dibuixar (acotat a MAX_ICONS, mai negatiu).
|
||||
auto lifeIconCount(int lives) -> int {
|
||||
return std::clamp(lives, 0, Defaults::Hud::Lives::MAX_ICONS);
|
||||
// Mida d'un slot = alçada de la majúscula del dígit (mètrica del glif).
|
||||
auto slotSize(float scale) -> float {
|
||||
return Graphics::VectorText::getTextHeight(scale);
|
||||
}
|
||||
|
||||
// Ample del bloc de vides (0 si no hi ha vides). N icones = (N-1) passos
|
||||
// de separació + l'amplada d'una icona.
|
||||
auto livesBlockWidth(int lives) -> float {
|
||||
const int N = lifeIconCount(lives);
|
||||
if (N <= 0) {
|
||||
// Ample del bloc de slots: constant, independent de les vides. NUM_SLOTS
|
||||
// slots al pas del dígit (l'últim slot ocupa la seva pròpia mida).
|
||||
auto slotsBlockWidth(float scale, float spacing) -> float {
|
||||
if (NUM_SLOTS <= 0) {
|
||||
return 0.0F;
|
||||
}
|
||||
const float ICON_H = lifeIconHeight();
|
||||
const float STEP = ICON_H * Defaults::Hud::Lives::ICON_SPACING_FACTOR;
|
||||
return (static_cast<float>(N - 1) * STEP) + ICON_H;
|
||||
return (static_cast<float>(NUM_SLOTS - 1) * digitPitch(scale, spacing)) + slotSize(scale);
|
||||
}
|
||||
|
||||
// Dibuixa les vides com a icones de la nau (apuntant amunt, color del
|
||||
// jugador). El glow el posa el shader. x_left = vora esquerra del bloc.
|
||||
void drawLives(Rendering::Renderer* renderer,
|
||||
// Dibuixa els slots de vides com a naus en miniatura en posicions FIXES.
|
||||
// Slot amb vida disponible (repuesto) → color encès; slot buit → atenuat.
|
||||
// Repuestos = vides − 1 (la nau en joc no compta com a slot).
|
||||
void drawSlots(Rendering::Renderer* renderer,
|
||||
const std::shared_ptr<Graphics::Shape>& shape,
|
||||
int lives,
|
||||
SDL_Color color,
|
||||
SDL_Color bright,
|
||||
SDL_Color dim,
|
||||
float x_left,
|
||||
float center_y) {
|
||||
const int N = lifeIconCount(lives);
|
||||
if (N <= 0 || !shape) {
|
||||
float center_y,
|
||||
float scale,
|
||||
float spacing) {
|
||||
if (NUM_SLOTS <= 0 || !shape) {
|
||||
return;
|
||||
}
|
||||
const float ICON_H = lifeIconHeight();
|
||||
const float STEP = ICON_H * Defaults::Hud::Lives::ICON_SPACING_FACTOR;
|
||||
// Escala que ajusta el cercle circumscrit de la shape a l'alçada
|
||||
// objectiu (mida predictible independent del .shp).
|
||||
const float SIZE = slotSize(scale);
|
||||
const float PITCH = digitPitch(scale, spacing);
|
||||
// Escala que ajusta el cercle circumscrit de la shape a la mida del
|
||||
// slot (mida predictible independent del .shp).
|
||||
const float RADIUS = shape->getBoundingRadius();
|
||||
const float SCALE = (RADIUS > 0.001F) ? (ICON_H / (2.0F * RADIUS)) : 1.0F;
|
||||
for (int i = 0; i < N; i++) {
|
||||
const Vec2 POS = {.x = x_left + (ICON_H / 2.0F) + (static_cast<float>(i) * STEP), .y = center_y};
|
||||
Rendering::renderShape(renderer, shape, POS, 0.0F, SCALE, 1.0F, 1.0F, color);
|
||||
const float ICON_SCALE = (RADIUS > 0.001F) ? (SIZE / (2.0F * RADIUS)) : 1.0F;
|
||||
const int FILLED = std::clamp(lives - 1, 0, NUM_SLOTS);
|
||||
for (int i = 0; i < NUM_SLOTS; i++) {
|
||||
const SDL_Color COLOR = (i < FILLED) ? bright : dim;
|
||||
const Vec2 POS = {.x = x_left + (SIZE / 2.0F) + (static_cast<float>(i) * PITCH), .y = center_y};
|
||||
Rendering::renderShape(renderer, shape, POS, 0.0F, ICON_SCALE, 1.0F, 1.0F, COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,13 +184,14 @@ namespace Systems::InitHud {
|
||||
bool right_align) {
|
||||
const float TOP_Y = center_y - (Graphics::VectorText::getTextHeight(scale) / 2.0F);
|
||||
const float W_SCORE = Graphics::VectorText::getTextWidth(score, scale, spacing);
|
||||
const float W_LIVES = livesBlockWidth(lives);
|
||||
const float BLOCK_W = W_SCORE + Defaults::Hud::Layout::BLOCK_INNER_GAP + W_LIVES;
|
||||
const float GAP = digitPitch(scale, spacing); // separació punts↔slots = un pas de dígit
|
||||
const float W_LIVES = slotsBlockWidth(scale, spacing);
|
||||
const float BLOCK_W = W_SCORE + GAP + W_LIVES;
|
||||
|
||||
float x = right_align ? (anchor_x - BLOCK_W) : anchor_x;
|
||||
drawScore(text, score, bright, dim, x, TOP_Y, scale, spacing);
|
||||
x += W_SCORE + Defaults::Hud::Layout::BLOCK_INNER_GAP;
|
||||
drawLives(renderer, shape, lives, bright, x, center_y);
|
||||
x += W_SCORE + GAP;
|
||||
drawSlots(renderer, shape, lives, bright, dim, x, center_y, scale, spacing);
|
||||
}
|
||||
|
||||
// Pinta el nivell centrat: etiqueta "NIVELL" en verd atenuat i el número
|
||||
|
||||
Reference in New Issue
Block a user