131 lines
5.9 KiB
C++
131 lines
5.9 KiB
C++
// init_hud_animator.cpp - Implementación de la animación inicial del HUD
|
|
|
|
#include "game/systems/init_hud_animator.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
#include "core/defaults.hpp"
|
|
#include "core/defaults/hud.hpp"
|
|
#include "core/math/easing.hpp"
|
|
#include "core/rendering/line_renderer.hpp"
|
|
|
|
namespace Systems::InitHud {
|
|
|
|
auto computeRangeProgress(float global_progress,
|
|
float ratio_init,
|
|
float ratio_end) -> float {
|
|
if (ratio_init >= ratio_end) {
|
|
return (global_progress >= ratio_end) ? 1.0F : 0.0F;
|
|
}
|
|
if (global_progress < ratio_init) {
|
|
return 0.0F;
|
|
}
|
|
if (global_progress > ratio_end) {
|
|
return 1.0F;
|
|
}
|
|
return (global_progress - ratio_init) / (ratio_end - ratio_init);
|
|
}
|
|
|
|
auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
|
|
const float EASED = Easing::easeOutQuad(progress);
|
|
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
|
// 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_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED);
|
|
return Vec2{.x = final_position.x, .y = Y_ANIM};
|
|
}
|
|
|
|
void drawBordersAnimated(Rendering::Renderer* renderer, float progress) {
|
|
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
|
const float EASED = Easing::easeOutQuad(progress);
|
|
|
|
const int X1 = static_cast<int>(zone.x);
|
|
const int Y1 = static_cast<int>(zone.y);
|
|
const int X2 = static_cast<int>(zone.x + zone.w);
|
|
const int Y2 = static_cast<int>(zone.y + zone.h);
|
|
const int CX = (X1 + X2) / 2;
|
|
|
|
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) {
|
|
const float P = std::min(EASED / PHASE_1_END, 1.0F);
|
|
const int X_LEFT = static_cast<int>(CX - ((CX - X1) * P));
|
|
const int X_RIGHT = static_cast<int>(CX + ((X2 - CX) * P));
|
|
Rendering::linea(renderer, CX, Y1, X_LEFT, Y1);
|
|
Rendering::linea(renderer, CX, Y1, X_RIGHT, Y1);
|
|
}
|
|
|
|
// Fase 2: laterales bajan.
|
|
if (EASED > PHASE_1_END) {
|
|
const float P = std::min((EASED - PHASE_1_END) / (PHASE_2_END - PHASE_1_END), 1.0F);
|
|
const int Y_BOTTOM = static_cast<int>(Y1 + ((Y2 - Y1) * P));
|
|
Rendering::linea(renderer, X1, Y1, X1, Y_BOTTOM);
|
|
Rendering::linea(renderer, X2, Y1, X2, Y_BOTTOM);
|
|
}
|
|
|
|
// Fase 3: línea inferior crece desde los lados hacia el centro.
|
|
if (EASED > PHASE_2_END) {
|
|
const float P = (EASED - PHASE_2_END) / (1.0F - PHASE_2_END);
|
|
const int X_LEFT = static_cast<int>(X1 + ((CX - X1) * P));
|
|
const int X_RIGHT = static_cast<int>(X2 - ((X2 - CX) * P));
|
|
Rendering::linea(renderer, X1, Y2, X_LEFT, Y2);
|
|
Rendering::linea(renderer, X2, Y2, X_RIGHT, Y2);
|
|
}
|
|
}
|
|
|
|
void drawScoreboardSegmentsAt(const Graphics::VectorText& text,
|
|
const ScoreboardSegments& segments,
|
|
const Vec2& center,
|
|
float scale,
|
|
float spacing) {
|
|
// Separadors entre segments (preservant el layout legacy: " ", " ", " ", " ").
|
|
const float W_SEP1 = Graphics::VectorText::getTextWidth(" ", scale, spacing);
|
|
const float W_SEP2 = Graphics::VectorText::getTextWidth(" ", scale, spacing);
|
|
|
|
const float W_SP1 = Graphics::VectorText::getTextWidth(segments.score_p1, scale, spacing);
|
|
const float W_LP1 = Graphics::VectorText::getTextWidth(segments.lives_p1, scale, spacing);
|
|
const float W_LV = Graphics::VectorText::getTextWidth(segments.level, scale, spacing);
|
|
const float W_SP2 = Graphics::VectorText::getTextWidth(segments.score_p2, scale, spacing);
|
|
const float W_LP2 = Graphics::VectorText::getTextWidth(segments.lives_p2, scale, spacing);
|
|
|
|
const float TOTAL = W_SP1 + W_SEP1 + W_LP1 + W_SEP2 + W_LV + W_SEP2 + W_SP2 + W_SEP1 + W_LP2;
|
|
|
|
const float HEIGHT = Graphics::VectorText::getTextHeight(scale);
|
|
const float TOP_Y = center.y - (HEIGHT / 2.0F);
|
|
float x = center.x - (TOTAL / 2.0F);
|
|
|
|
text.render(segments.score_p1, {.x = x, .y = TOP_Y}, scale, spacing, 1.0F, Defaults::Hud::Colors::SCORE_P1);
|
|
x += W_SP1 + W_SEP1;
|
|
text.render(segments.lives_p1, {.x = x, .y = TOP_Y}, scale, spacing, 1.0F, Defaults::Hud::Colors::LIVES);
|
|
x += W_LP1 + W_SEP2;
|
|
text.render(segments.level, {.x = x, .y = TOP_Y}, scale, spacing, 1.0F, Defaults::Hud::Colors::LEVEL);
|
|
x += W_LV + W_SEP2;
|
|
text.render(segments.score_p2, {.x = x, .y = TOP_Y}, scale, spacing, 1.0F, Defaults::Hud::Colors::SCORE_P2);
|
|
x += W_SP2 + W_SEP1;
|
|
text.render(segments.lives_p2, {.x = x, .y = TOP_Y}, scale, spacing, 1.0F, Defaults::Hud::Colors::LIVES);
|
|
}
|
|
|
|
void drawScoreboardAnimated(const Graphics::VectorText& text,
|
|
const ScoreboardSegments& segments,
|
|
float progress) {
|
|
const float EASED = Easing::easeOutQuad(progress);
|
|
|
|
constexpr float SCALE = Defaults::Hud::SCOREBOARD_TEXT_SCALE;
|
|
constexpr float SPACING = Defaults::Hud::SCOREBOARD_TEXT_SPACING;
|
|
const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD;
|
|
const float CENTRE_X = scoreboard_zone.w / 2.0F;
|
|
const float Y_FINAL = scoreboard_zone.y + (scoreboard_zone.h / 2.0F);
|
|
// Posición inicial: fuera de la pantalla por debajo.
|
|
const auto Y_INI = static_cast<float>(Defaults::Game::HEIGHT);
|
|
const float Y_ANIM = Y_INI + ((Y_FINAL - Y_INI) * EASED);
|
|
|
|
drawScoreboardSegmentsAt(text, segments, {.x = CENTRE_X, .y = Y_ANIM}, SCALE, SPACING);
|
|
}
|
|
|
|
} // namespace Systems::InitHud
|