tweak(hud): vides com a icones de la nau en miniatura en lloc d'un número
This commit is contained in:
@@ -814,7 +814,7 @@ void GameScene::drawInitHudState() {
|
||||
}
|
||||
|
||||
if (score_progress > 0.0F) {
|
||||
Systems::InitHud::drawScoreboardAnimated(text_, buildScoreboardData(), score_progress);
|
||||
Systems::InitHud::drawScoreboardAnimated(sdl_.getRenderer(), text_, buildScoreboardData(), score_progress);
|
||||
}
|
||||
|
||||
if (ship1_progress > 0.0F && match_config_.player1_active && ships_[0].isActive()) {
|
||||
@@ -933,7 +933,7 @@ void GameScene::drawScoreboard() {
|
||||
text_.renderCentered(Locale::get().text("demo.banner"), CENTER, SCALE, SPACING);
|
||||
return;
|
||||
}
|
||||
Systems::InitHud::drawScoreboardAt(text_, buildScoreboardData(), CENTER.y, SCALE, SPACING);
|
||||
Systems::InitHud::drawScoreboardAt(sdl_.getRenderer(), text_, buildScoreboardData(), CENTER.y, SCALE, SPACING);
|
||||
}
|
||||
|
||||
auto GameScene::buildScoreboardData() const -> Systems::InitHud::ScoreboardData {
|
||||
@@ -950,6 +950,11 @@ auto GameScene::buildScoreboardData() const -> Systems::InitHud::ScoreboardData
|
||||
out.score_p2 = match_config_.player2_active ? FORMAT_SCORE(score_per_player_[1]) : "000000";
|
||||
out.lives_p2 = match_config_.player2_active ? lives_per_player_[1] : 0;
|
||||
|
||||
// Shapes de les naus per a les icones de vides (reutilitza la geometria ja
|
||||
// carregada de cada Ship).
|
||||
out.shape_p1 = ships_[0].getShape();
|
||||
out.shape_p2 = ships_[1].getShape();
|
||||
|
||||
// Nivell: etiqueta localitzada + número a 2 dígits (separats per pintar-los
|
||||
// amb tonalitats distintes).
|
||||
const uint8_t STAGE_NUM = stage_manager_->getCurrentStage();
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "core/defaults/hud.hpp"
|
||||
#include "core/math/easing.hpp"
|
||||
#include "core/rendering/line_renderer.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
|
||||
namespace Systems::InitHud {
|
||||
|
||||
@@ -80,10 +81,50 @@ namespace Systems::InitHud {
|
||||
|
||||
namespace {
|
||||
|
||||
// Vides com a text (2 dígits) — provisional fins a migrar-les a icones.
|
||||
auto livesText(int lives) -> std::string {
|
||||
const std::string S = std::to_string(lives);
|
||||
return (lives < 10) ? "0" + S : S;
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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,
|
||||
const std::shared_ptr<Graphics::Shape>& shape,
|
||||
int lives,
|
||||
SDL_Color color,
|
||||
float x_left,
|
||||
float center_y) {
|
||||
const int N = lifeIconCount(lives);
|
||||
if (N <= 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta la puntuació amb els zeros de farciment previs al primer dígit
|
||||
@@ -112,27 +153,30 @@ namespace Systems::InitHud {
|
||||
}
|
||||
|
||||
// Pinta el bloc d'un jugador "punts vides" amb el seu color (punts amb
|
||||
// zeros atenuats, vides en brillant). Si right_align, el bloc acaba a
|
||||
// anchor_x (ancorat a la dreta); si no, comença a anchor_x (esquerra).
|
||||
void drawPlayerBlock(const Graphics::VectorText& text,
|
||||
// zeros atenuats, vides com a icones de nau en brillant). Si right_align,
|
||||
// el bloc acaba a anchor_x (ancorat a la dreta); si no, comença a
|
||||
// anchor_x (esquerra).
|
||||
void drawPlayerBlock(Rendering::Renderer* renderer,
|
||||
const Graphics::VectorText& text,
|
||||
const std::shared_ptr<Graphics::Shape>& shape,
|
||||
const std::string& score,
|
||||
int lives,
|
||||
SDL_Color bright,
|
||||
SDL_Color dim,
|
||||
float anchor_x,
|
||||
float top_y,
|
||||
float center_y,
|
||||
float scale,
|
||||
float spacing,
|
||||
bool right_align) {
|
||||
const std::string LIVES_STR = livesText(lives);
|
||||
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 = Graphics::VectorText::getTextWidth(LIVES_STR, scale, spacing);
|
||||
const float W_LIVES = livesBlockWidth(lives);
|
||||
const float BLOCK_W = W_SCORE + Defaults::Hud::Layout::BLOCK_INNER_GAP + W_LIVES;
|
||||
|
||||
float x = right_align ? (anchor_x - BLOCK_W) : anchor_x;
|
||||
drawScore(text, score, bright, dim, x, top_y, scale, spacing);
|
||||
drawScore(text, score, bright, dim, x, TOP_Y, scale, spacing);
|
||||
x += W_SCORE + Defaults::Hud::Layout::BLOCK_INNER_GAP;
|
||||
text.render(LIVES_STR, {.x = x, .y = top_y}, scale, spacing, 1.0F, bright);
|
||||
drawLives(renderer, shape, lives, bright, x, center_y);
|
||||
}
|
||||
|
||||
// Pinta el nivell centrat: etiqueta "NIVELL" en verd atenuat i el número
|
||||
@@ -154,7 +198,8 @@ namespace Systems::InitHud {
|
||||
|
||||
} // namespace
|
||||
|
||||
void drawScoreboardAt(const Graphics::VectorText& text,
|
||||
void drawScoreboardAt(Rendering::Renderer* renderer,
|
||||
const Graphics::VectorText& text,
|
||||
const ScoreboardData& data,
|
||||
float center_y,
|
||||
float scale,
|
||||
@@ -165,12 +210,13 @@ namespace Systems::InitHud {
|
||||
const float RIGHT = play.x + play.w;
|
||||
const float TOP_Y = center_y - (Graphics::VectorText::getTextHeight(scale) / 2.0F);
|
||||
|
||||
drawPlayerBlock(text, data.score_p1, data.lives_p1, Defaults::Hud::Colors::P1_BRIGHT, Defaults::Hud::Colors::P1_DIM, LEFT, TOP_Y, scale, spacing, false);
|
||||
drawPlayerBlock(text, data.score_p2, data.lives_p2, Defaults::Hud::Colors::P2_BRIGHT, Defaults::Hud::Colors::P2_DIM, RIGHT, TOP_Y, scale, spacing, true);
|
||||
drawPlayerBlock(renderer, text, data.shape_p1, data.score_p1, data.lives_p1, Defaults::Hud::Colors::P1_BRIGHT, Defaults::Hud::Colors::P1_DIM, LEFT, center_y, scale, spacing, false);
|
||||
drawPlayerBlock(renderer, text, data.shape_p2, data.score_p2, data.lives_p2, Defaults::Hud::Colors::P2_BRIGHT, Defaults::Hud::Colors::P2_DIM, RIGHT, center_y, scale, spacing, true);
|
||||
drawLevel(text, data.level_label, data.level_value, TOP_Y, scale, spacing);
|
||||
}
|
||||
|
||||
void drawScoreboardAnimated(const Graphics::VectorText& text,
|
||||
void drawScoreboardAnimated(Rendering::Renderer* renderer,
|
||||
const Graphics::VectorText& text,
|
||||
const ScoreboardData& data,
|
||||
float progress) {
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
@@ -183,7 +229,7 @@ namespace Systems::InitHud {
|
||||
const auto Y_INI = static_cast<float>(Defaults::Game::HEIGHT);
|
||||
const float Y_ANIM = Y_INI + ((Y_FINAL - Y_INI) * EASED);
|
||||
|
||||
drawScoreboardAt(text, data, Y_ANIM, SCALE, SPACING);
|
||||
drawScoreboardAt(renderer, text, data, Y_ANIM, SCALE, SPACING);
|
||||
}
|
||||
|
||||
} // namespace Systems::InitHud
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "core/graphics/shape.hpp"
|
||||
#include "core/graphics/vector_text.hpp"
|
||||
#include "core/rendering/render_context.hpp"
|
||||
#include "core/types.hpp"
|
||||
@@ -32,6 +34,9 @@ namespace Systems::InitHud {
|
||||
int lives_p2{0}; // vides P2
|
||||
std::string level_label; // ex: "NIVELL "
|
||||
std::string level_value; // ex: "01"
|
||||
// Shapes de les naus per dibuixar les vides com a icones en miniatura.
|
||||
std::shared_ptr<Graphics::Shape> shape_p1;
|
||||
std::shared_ptr<Graphics::Shape> shape_p2;
|
||||
};
|
||||
|
||||
// Convierte un progreso global 0..1 al sub-progreso de un elemento que solo
|
||||
@@ -55,8 +60,10 @@ namespace Systems::InitHud {
|
||||
|
||||
// Dibuixa el marcador en tres blocs ancorats a la fila d'alçada `center_y`:
|
||||
// bloc P1 a l'esquerra, bloc P2 a la dreta i nivell centrat. Cada bloc amb
|
||||
// el seu color (Defaults::Hud::Colors).
|
||||
void drawScoreboardAt(const Graphics::VectorText& text,
|
||||
// el seu color (Defaults::Hud::Colors). El renderer cal per dibuixar les
|
||||
// icones de vides (shapes de nau).
|
||||
void drawScoreboardAt(Rendering::Renderer* renderer,
|
||||
const Graphics::VectorText& text,
|
||||
const ScoreboardData& data,
|
||||
float center_y,
|
||||
float scale,
|
||||
@@ -64,7 +71,8 @@ namespace Systems::InitHud {
|
||||
|
||||
// Dibuixa el marcador pujant des de fora de la pantalla fins a la seva
|
||||
// posició final amb easing. Delega a drawScoreboardAt.
|
||||
void drawScoreboardAnimated(const Graphics::VectorText& text,
|
||||
void drawScoreboardAnimated(Rendering::Renderer* renderer,
|
||||
const Graphics::VectorText& text,
|
||||
const ScoreboardData& data,
|
||||
float progress);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user