marcador provisional

This commit is contained in:
2026-04-06 14:53:58 +02:00
parent 67bf6b2017
commit 4c5e1e5470
12 changed files with 180 additions and 181 deletions

View File

@@ -2,67 +2,45 @@
#include <SDL3/SDL.h>
#include <string>
#include <utility>
#include <vector>
#include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource
#include "game/entities/player.hpp" // Para Player::skinToAnimationPath
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
#include "utils/defines.hpp" // Para BLOCK
#include "utils/utils.hpp"
#include "core/locale/locale.hpp"
#include "core/rendering/screen.hpp"
#include "core/rendering/surface.hpp"
#include "core/rendering/text.hpp"
#include "core/resources/resource_cache.hpp"
#include "game/options.hpp"
#include "utils/defines.hpp"
// Constructor
Scoreboard::Scoreboard(std::shared_ptr<Data> data)
: item_surface_(Resource::Cache::get()->getSurface("items.gif")),
data_(std::move(std::move(data))) {
: data_(std::move(data)) {
const float SURFACE_WIDTH = Options::game.width;
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE;
// Reserva memoria para los objetos
const std::string PLAYER_ANIM_PATH = Player::skinToAnimationPath(Options::game.player_skin);
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(PLAYER_ANIM_PATH);
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
player_sprite_->setCurrentAnimation("default");
constexpr float SURFACE_HEIGHT = 24.0F; // 3 líneas de 8px
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
// Inicializa el color de items
items_color_ = 14;
// Inicializa el vector de colores
color_ = {2, 6, 8, 10, 12, 14, 3, 7, 9, 11, 13, 15};
}
// Pinta el objeto en pantalla
void Scoreboard::render() {
return;
surface_->render(nullptr, &surface_dest_);
}
// Actualiza las variables del objeto
void Scoreboard::update(float delta_time) {
// Acumular tiempo para animaciones
time_accumulator_ += delta_time;
// Actualiza el color de la cantidad de items recogidos
updateItemsColor(delta_time);
// Dibuja la textura
fillTexture();
if (!is_paused_) {
// Si está en pausa no se actualiza el reloj
clock_ = getTime();
}
}
// Obtiene el tiempo transcurrido de partida
auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-convert-member-functions-to-static)
auto Scoreboard::getTime() -> Scoreboard::ClockData {
const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
ClockData time;
@@ -74,51 +52,27 @@ auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-con
return time;
}
// Actualiza el sprite del jugador con la skin actual
void Scoreboard::refreshPlayerSkin() {
const std::string PLAYER_ANIM_PATH = Player::skinToAnimationPath(Options::game.player_skin);
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(PLAYER_ANIM_PATH);
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
player_sprite_->setCurrentAnimation("default");
}
// Pone el marcador en modo pausa
void Scoreboard::setPaused(bool value) {
if (is_paused_ == value) {
// Evita ejecutar lógica si el estado no cambia
return;
}
if (is_paused_ == value) { return; }
is_paused_ = value;
if (is_paused_) {
// Guarda el tiempo actual al pausar
paused_time_ = SDL_GetTicks();
} else {
// Calcula el tiempo pausado acumulado al reanudar
paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
}
}
// Actualiza el color de la cantidad de items recogidos
void Scoreboard::updateItemsColor(float delta_time) {
if (!data_->jail_is_open) {
return;
}
if (!data_->jail_is_open) { return; }
items_color_timer_ += delta_time;
// Resetear timer cada 2 ciclos (0.666s total)
if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) {
items_color_timer_ = 0.0F;
}
// Alternar color cada ITEMS_COLOR_BLINK_DURATION
if (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) {
items_color_ = 14;
} else {
items_color_ = 6;
}
items_color_ = (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) ? VALUE_COLOR : 6;
}
// Devuelve la cantidad de minutos de juego transcurridos
@@ -126,56 +80,80 @@ auto Scoreboard::getMinutes() -> int {
return getTime().minutes;
}
// Dibuja los elementos del marcador en la textura
// Dibuja los elementos del marcador en la surface
void Scoreboard::fillTexture() {
// Empieza a dibujar en la textura
auto previuos_renderer = Screen::get()->getRendererSurface();
auto previous_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(surface_);
// Limpia la textura
surface_->clear(0);
// Dibuja las vidas
const int WALK_FRAMES = player_sprite_->getCurrentAnimationSize();
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % (WALK_FRAMES * 2);
const int FRAME = DESP % WALK_FRAMES;
player_sprite_->setCurrentAnimationFrame(FRAME);
player_sprite_->setPosY(LINE2_Y);
for (int i = 0; i < data_->lives; ++i) {
player_sprite_->setPosX(LIVES_START_X + (LIVES_SPACING * i) + DESP);
const int INDEX = i % color_.size();
player_sprite_->render(1, color_.at(INDEX));
}
auto text = Resource::Cache::get()->getText("8bithud");
const int CANVAS_W = static_cast<int>(Options::game.width);
const std::string SEP = " - ";
const int MONO_W = 7; // Ancho fijo por carácter monoespaciado (dígitos + separador)
// Muestra si suena la música
// Valores formateados
const std::string LIVES_STR = std::to_string(data_->lives);
const std::string ITEMS_STR = std::to_string(data_->items);
const std::string TIME_STR = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10)
+ clock_.separator
+ std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
// --- Línea 1: vides X - objectes X - temps MM:SS (centrada) ---
const std::string LIVES_LABEL = Locale::get()->get("scoreboard.lives");
const std::string ITEMS_LABEL = Locale::get()->get("scoreboard.items");
const std::string TIME_LABEL = Locale::get()->get("scoreboard.time");
// Ancho total: labels proporcionales + valores monoespaciados
const int LINE1_W = text->length(LIVES_LABEL) + text->lengthMono(LIVES_STR, MONO_W)
+ text->length(SEP) + text->length(ITEMS_LABEL) + text->lengthMono(ITEMS_STR, MONO_W)
+ text->length(SEP) + text->length(TIME_LABEL) + text->lengthMono(TIME_STR, MONO_W);
int x = (CANVAS_W - LINE1_W) / 2;
text->writeColored(x, LINE1_Y, LIVES_LABEL, LABEL_COLOR);
x += text->length(LIVES_LABEL);
text->writeColoredMono(x, LINE1_Y, LIVES_STR, VALUE_COLOR, MONO_W);
x += text->lengthMono(LIVES_STR, MONO_W);
text->writeColored(x, LINE1_Y, SEP, LABEL_COLOR);
x += text->length(SEP);
text->writeColored(x, LINE1_Y, ITEMS_LABEL, LABEL_COLOR);
x += text->length(ITEMS_LABEL);
text->writeColoredMono(x, LINE1_Y, ITEMS_STR, items_color_, MONO_W);
x += text->lengthMono(ITEMS_STR, MONO_W);
text->writeColored(x, LINE1_Y, SEP, LABEL_COLOR);
x += text->length(SEP);
text->writeColored(x, LINE1_Y, TIME_LABEL, LABEL_COLOR);
x += text->length(TIME_LABEL);
text->writeColoredMono(x, LINE1_Y, TIME_STR, VALUE_COLOR, MONO_W);
// --- Línea 2: indicadores activos (centrada) ---
std::vector<std::string> indicators;
if (data_->music) {
const Uint8 C = data_->color;
SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
item_surface_->renderWithColorReplace(MUSIC_ICON_X, LINE2_Y, 1, C, &clip);
indicators.push_back(Locale::get()->get("scoreboard.music_on"));
}
// Escribe los textos
auto text = Resource::Cache::get()->getText("smb2");
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
text->writeColored(ITEMS_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.items"), data_->color); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(ITEMS_VALUE_X, LINE1_Y, ITEMS_TEXT, items_color_);
text->writeColored(TIME_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.time"), data_->color); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(TIME_VALUE_X, LINE1_Y, TIME_TEXT, 14);
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
text->writeColored(ROOMS_LABEL_X, LINE2_Y, Locale::get()->get("scoreboard.rooms"), 14); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(ROOMS_VALUE_X, LINE2_Y, ROOMS_TEXT, 14);
// Indicadores de trucos activos (fuente 8bithud)
auto cheat_text = Resource::Cache::get()->getText("8bithud");
if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
cheat_text->writeColored(CHEAT_INF_LIVES_X, CHEAT_INF_LIVES_Y, Locale::get()->get("scoreboard.cheat_infinite_lives"), data_->color); // NOLINT(readability-static-accessed-through-instance)
indicators.push_back(Locale::get()->get("scoreboard.cheat_infinite_lives"));
}
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
cheat_text->writeColored(CHEAT_INVINCIBLE_X, CHEAT_INVINCIBLE_Y, Locale::get()->get("scoreboard.cheat_invincibility"), data_->color); // NOLINT(readability-static-accessed-through-instance)
indicators.push_back(Locale::get()->get("scoreboard.cheat_invincibility"));
}
// Deja el renderizador como estaba
Screen::get()->setRendererSurface(previuos_renderer);
}
if (!indicators.empty()) {
int line2_w = 0;
for (size_t i = 0; i < indicators.size(); ++i) {
if (i > 0) { line2_w += text->length(SEP); }
line2_w += text->length(indicators[i]);
}
x = (CANVAS_W - line2_w) / 2;
for (size_t i = 0; i < indicators.size(); ++i) {
if (i > 0) {
text->writeColored(x, LINE2_Y, SEP, LABEL_COLOR);
x += text->length(SEP);
}
text->writeColored(x, LINE2_Y, indicators[i], LABEL_COLOR);
x += text->length(indicators[i]);
}
}
Screen::get()->setRendererSurface(previous_renderer);
}

View File

@@ -3,11 +3,10 @@
#include <SDL3/SDL.h>
#include <memory> // Para shared_ptr
#include <string> // Para string, basic_string
#include <string> // Para string
#include <utility>
#include <vector> // Para vector
class AnimatedSprite; // lines 10-10
class Surface; // lines 11-11
class Surface;
class Scoreboard {
public:
@@ -28,58 +27,43 @@ class Scoreboard {
void render(); // Pinta el objeto en pantalla
void update(float delta_time); // Actualiza las variables del objeto
void setPaused(bool value); // Pone el marcador en modo pausa
void refreshPlayerSkin(); // Actualiza el sprite del jugador con la skin actual
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
private:
// Tipos anidados
struct ClockData {
int hours{0}; // Horas transcurridas
int minutes{0}; // Minutos transcurridos
int seconds{0}; // Segundos transcurridos
std::string separator{":"}; // Separador para mostrar el tiempo
int hours{0};
int minutes{0};
int seconds{0};
std::string separator{":"};
};
// Constantes de tiempo
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F;
// Posición de los elementos del marcador (en pixels, Tile::SIZE = 8)
static constexpr int LINE1_Y = 8; // Fila superior (1 * Tile::SIZE)
static constexpr int LINE2_Y = 24; // Fila inferior (3 * Tile::SIZE)
static constexpr int ITEMS_LABEL_X = 8; // "TRESORS PILLATS" / "ITEMS COLLECTED"
static constexpr int ITEMS_VALUE_X = 136; // Valor numérico de items
static constexpr int TIME_LABEL_X = 160; // "HORA" / "TIME"
static constexpr int TIME_VALUE_X = 208; // Valor numérico del tiempo
static constexpr int LIVES_START_X = 8; // Primera vida (sprite)
static constexpr int LIVES_SPACING = 16; // Separación entre vidas
static constexpr int MUSIC_ICON_X = 160; // Icono de música
static constexpr int ROOMS_LABEL_X = 176; // "SALES" / "ROOMS"
static constexpr int ROOMS_VALUE_X = 224; // Valor numérico de salas
static constexpr int CHEAT_INF_LIVES_X = 176; // Indicador "vides inf" / "inf lives"
static constexpr int CHEAT_INF_LIVES_Y = 34; // Posición Y del indicador de vidas infinitas
static constexpr int CHEAT_INVINCIBLE_X = 231; // Indicador "inv"
static constexpr int CHEAT_INVINCIBLE_Y = 34; // Posición Y del indicador de invencibilidad
// Posición de los elementos (2 líneas centradas verticalmente en surface de 24px)
static constexpr int LINE1_Y = 5;
static constexpr int LINE2_Y = 13;
// Colores
static constexpr Uint8 LABEL_COLOR = 11;
static constexpr Uint8 VALUE_COLOR = 9;
// Métodos privados
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
void updateItemsColor(float delta_time); // Actualiza el color de la cantidad de items recogidos
void fillTexture(); // Dibuja los elementos del marcador en la surface
auto getTime() -> ClockData;
void updateItemsColor(float delta_time);
void fillTexture();
// Objetos y punteros
std::shared_ptr<AnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador
std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador
std::shared_ptr<Data> data_;
std::shared_ptr<Surface> surface_;
// Variables de estado
std::vector<Uint8> color_; // Vector con los colores del objeto
bool is_paused_{false}; // Indica si el marcador esta en modo pausa
Uint32 paused_time_{0}; // Milisegundos que ha estado el marcador en pausa
Uint32 paused_time_elapsed_{0}; // Tiempo acumulado en pausa
ClockData clock_{}; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida
Uint8 items_color_{0}; // Color de la cantidad de items recogidos
SDL_FRect surface_dest_{}; // Rectangulo donde dibujar la surface del marcador
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
float items_color_timer_{0.0F}; // Timer para parpadeo de color de items
bool is_paused_{false};
Uint32 paused_time_{0};
Uint32 paused_time_elapsed_{0};
ClockData clock_{};
Uint8 items_color_{VALUE_COLOR};
SDL_FRect surface_dest_{};
float items_color_timer_{0.0F};
};