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

@@ -122,11 +122,12 @@ ui:
vsync_disabled: "V-SYNC DESACTIVAT" vsync_disabled: "V-SYNC DESACTIVAT"
scoreboard: scoreboard:
items: "TRESORS PILLATS " lives: "vides "
time: " HORA " items: "objectes "
rooms: "SALES" time: "temps "
cheat_infinite_lives: "vides inf" music_on: "musica"
cheat_invincibility: "inv" cheat_infinite_lives: "vides infinites"
cheat_invincibility: "invencibilitat"
game: game:
music_enabled: "MÚSICA ACTIVADA" music_enabled: "MÚSICA ACTIVADA"

View File

@@ -122,11 +122,12 @@ ui:
vsync_disabled: "V-SYNC DISABLED" vsync_disabled: "V-SYNC DISABLED"
scoreboard: scoreboard:
items: "ITEMS COLLECTED " lives: "lives "
time: " TIME " items: "items "
rooms: "ROOMS" time: "time "
cheat_infinite_lives: "inf lives" music_on: "music"
cheat_invincibility: "inv" cheat_infinite_lives: "infinite lives"
cheat_invincibility: "invincibility"
game: game:
music_enabled: "MUSIC ENABLED" music_enabled: "MUSIC ENABLED"

View File

@@ -106,8 +106,7 @@ void RenderInfo::render() const {
// Todo en lowercase // Todo en lowercase
std::ranges::transform(line, line.begin(), [](unsigned char c) { return std::tolower(c); }); std::ranges::transform(line, line.begin(), [](unsigned char c) { return std::tolower(c); });
// Constantes visuales (igual que Console) // Constantes visuales
static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK
static constexpr Uint8 MSG_COLOR = 9; // PaletteColor::BRIGHT_GREEN static constexpr Uint8 MSG_COLOR = 9; // PaletteColor::BRIGHT_GREEN
static constexpr int TEXT_SIZE = 6; static constexpr int TEXT_SIZE = 6;
static constexpr int PADDING_V = (TEXT_SIZE / 2) - 1; static constexpr int PADDING_V = (TEXT_SIZE / 2) - 1;
@@ -119,16 +118,6 @@ void RenderInfo::render() const {
const int CONSOLE_Y = (Console::get() != nullptr) ? Console::get()->getVisibleHeight() : 0; const int CONSOLE_Y = (Console::get() != nullptr) ? Console::get()->getVisibleHeight() : 0;
const int Y = CONSOLE_Y + static_cast<int>(y_); const int Y = CONSOLE_Y + static_cast<int>(y_);
// Rectángulo de fondo: ancho completo, alto ajustado al texto
const SDL_FRect RECT = {
.x = 0.0F,
.y = static_cast<float>(Y),
.w = Options::game.width,
.h = static_cast<float>(TEXT_SIZE + (PADDING_V * 2))};
auto game_surface = Screen::get()->getGameSurface();
game_surface->fillRect(&RECT, BG_COLOR);
// game_surface->drawRectBorder(&RECT, BORDER_COLOR);
text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG,
static_cast<int>(Options::game.width / 2), static_cast<int>(Options::game.width / 2),
Y + PADDING_V, Y + PADDING_V,

View File

@@ -219,6 +219,37 @@ void Text::writeColored(int x, int y, const std::string& text, Uint8 color, int
} }
} }
// Escribe texto monoespaciado con color (cada glifo centrado en una celda de ancho fijo)
void Text::writeColoredMono(int x, int y, const std::string& text, Uint8 color, int cell_w) { // NOLINT(readability-convert-member-functions-to-static)
int shift = 0;
size_t pos = 0;
sprite_->setY(y);
while (pos < text.size()) {
uint32_t cp = nextCodepoint(text, pos);
auto it = offset_.find(cp);
if (it == offset_.end()) { it = offset_.find('?'); }
if (it != offset_.end()) {
const int GLYPH_OFFSET = (cell_w - it->second.w) / 2;
sprite_->setClip(it->second.x, it->second.y, box_width_, box_height_);
sprite_->setX(x + shift + GLYPH_OFFSET);
sprite_->render(1, color);
}
shift += cell_w;
}
}
// Obtiene la longitud en pixels de una cadena monoespaciada
auto Text::lengthMono(const std::string& text, int cell_w) const -> int {
size_t pos = 0;
int count = 0;
while (pos < text.size()) {
nextCodepoint(text, pos);
++count;
}
return count * cell_w;
}
// Escribe el texto con sombra // Escribe el texto con sombra
void Text::writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance, int kerning, int lenght) { void Text::writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance, int kerning, int lenght) {
writeColored(x + shadow_distance, y + shadow_distance, text, color, kerning, lenght); writeColored(x + shadow_distance, y + shadow_distance, text, color, kerning, lenght);

View File

@@ -48,7 +48,9 @@ class Text {
auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura
auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura
void writeColoredMono(int x, int y, const std::string& text, Uint8 color, int cell_w); // Escribe texto monoespaciado con color
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena [[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
[[nodiscard]] auto lengthMono(const std::string& text, int cell_w) const -> int; // Obtiene la longitud en pixels de una cadena monoespaciada
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter [[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
[[nodiscard]] auto glyphWidth(uint32_t codepoint, int kerning = 0) const -> int; // Devuelve el ancho en pixels de un glifo [[nodiscard]] auto glyphWidth(uint32_t codepoint, int kerning = 0) const -> int; // Devuelve el ancho en pixels de un glifo
[[nodiscard]] auto getGlyphClip(uint32_t codepoint) const -> SDL_FRect; // Devuelve el clip rect del glifo [[nodiscard]] auto getGlyphClip(uint32_t codepoint) const -> SDL_FRect; // Devuelve el clip rect del glifo

View File

@@ -414,9 +414,12 @@ void Player::switchBorders() {
// Aplica gravedad al jugador // Aplica gravedad al jugador
void Player::applyGravity(float delta_time) { void Player::applyGravity(float delta_time) {
// La gravedad solo se aplica cuando el jugador esta en el aire
if (state_ == State::ON_AIR) { if (state_ == State::ON_AIR) {
vy_ += GRAVITY_FORCE * delta_time; // Si está subiendo y ha soltado el botón de salto, gravedad aumentada para cortar el salto
const float GRAVITY = (vy_ < 0.0F && !wanna_jump_)
? GRAVITY_FORCE * LOW_JUMP_GRAVITY_MULT
: GRAVITY_FORCE;
vy_ += GRAVITY * delta_time;
vy_ = std::min(vy_, MAX_VY); vy_ = std::min(vy_, MAX_VY);
} }
} }
@@ -675,13 +678,17 @@ void Player::updateVelocity(float delta_time) {
if (target > 0.0F) { sprite_->setFlip(Flip::RIGHT); } if (target > 0.0F) { sprite_->setFlip(Flip::RIGHT); }
else if (target < 0.0F) { sprite_->setFlip(Flip::LEFT); } else if (target < 0.0F) { sprite_->setFlip(Flip::LEFT); }
// Aproximar vx_ al objetivo con paso limitado por la aceleración // En el aire: inercia (interpolación gradual). En suelo/rampa: respuesta inmediata.
if (state_ == State::ON_AIR) {
const float STEP = HORIZONTAL_ACCEL * delta_time; const float STEP = HORIZONTAL_ACCEL * delta_time;
if (vx_ < target) { if (vx_ < target) {
vx_ = std::min(vx_ + STEP, target); vx_ = std::min(vx_ + STEP, target);
} else if (vx_ > target) { } else if (vx_ > target) {
vx_ = std::max(vx_ - STEP, target); vx_ = std::max(vx_ - STEP, target);
} }
} else {
vx_ = target;
}
} }
// Aplica movimiento horizontal con colisión de muros // Aplica movimiento horizontal con colisión de muros

View File

@@ -38,6 +38,7 @@ class Player {
static constexpr float MAX_VY = 160.0F; // Velocidad vertical máxima en pixels/segundo static constexpr float MAX_VY = 160.0F; // Velocidad vertical máxima en pixels/segundo
static constexpr float JUMP_VELOCITY = -140.0F; // Velocidad inicial del salto en pixels/segundo static constexpr float JUMP_VELOCITY = -140.0F; // Velocidad inicial del salto en pixels/segundo
static constexpr float GRAVITY_FORCE = 360.0F; // Fuerza de gravedad en pixels/segundo² static constexpr float GRAVITY_FORCE = 360.0F; // Fuerza de gravedad en pixels/segundo²
static constexpr float LOW_JUMP_GRAVITY_MULT = 3.0F; // Multiplicador de gravedad al soltar el botón de salto (salto variable)
struct SpawnData { struct SpawnData {
float x = 0; float x = 0;

View File

@@ -2,67 +2,45 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <string>
#include <utility> #include <utility>
#include <vector>
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp"
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp"
#include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/surface.hpp"
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/text.hpp"
#include "core/rendering/text.hpp" // Para Text #include "core/resources/resource_cache.hpp"
#include "core/resources/resource_cache.hpp" // Para Resource #include "game/options.hpp"
#include "game/entities/player.hpp" // Para Player::skinToAnimationPath #include "utils/defines.hpp"
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
#include "utils/defines.hpp" // Para BLOCK
#include "utils/utils.hpp"
// Constructor // Constructor
Scoreboard::Scoreboard(std::shared_ptr<Data> data) Scoreboard::Scoreboard(std::shared_ptr<Data> data)
: item_surface_(Resource::Cache::get()->getSurface("items.gif")), : data_(std::move(data)) {
data_(std::move(std::move(data))) {
const float SURFACE_WIDTH = Options::game.width; const float SURFACE_WIDTH = Options::game.width;
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE; constexpr float SURFACE_HEIGHT = 24.0F; // 3 líneas de 8px
// 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");
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT); 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}; 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 // Pinta el objeto en pantalla
void Scoreboard::render() { void Scoreboard::render() {
return;
surface_->render(nullptr, &surface_dest_); surface_->render(nullptr, &surface_dest_);
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
void Scoreboard::update(float delta_time) { 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); updateItemsColor(delta_time);
// Dibuja la textura
fillTexture(); fillTexture();
if (!is_paused_) { if (!is_paused_) {
// Si está en pausa no se actualiza el reloj
clock_ = getTime(); clock_ = getTime();
} }
} }
// Obtiene el tiempo transcurrido de partida // 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_; const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
ClockData time; ClockData time;
@@ -74,51 +52,27 @@ auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-con
return time; 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 // Pone el marcador en modo pausa
void Scoreboard::setPaused(bool value) { void Scoreboard::setPaused(bool value) {
if (is_paused_ == value) { if (is_paused_ == value) { return; }
// Evita ejecutar lógica si el estado no cambia
return;
}
is_paused_ = value; is_paused_ = value;
if (is_paused_) { if (is_paused_) {
// Guarda el tiempo actual al pausar
paused_time_ = SDL_GetTicks(); paused_time_ = SDL_GetTicks();
} else { } else {
// Calcula el tiempo pausado acumulado al reanudar
paused_time_elapsed_ += SDL_GetTicks() - paused_time_; paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
} }
} }
// Actualiza el color de la cantidad de items recogidos // Actualiza el color de la cantidad de items recogidos
void Scoreboard::updateItemsColor(float delta_time) { void Scoreboard::updateItemsColor(float delta_time) {
if (!data_->jail_is_open) { if (!data_->jail_is_open) { return; }
return;
}
items_color_timer_ += delta_time; items_color_timer_ += delta_time;
// Resetear timer cada 2 ciclos (0.666s total)
if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) { if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) {
items_color_timer_ = 0.0F; items_color_timer_ = 0.0F;
} }
items_color_ = (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) ? VALUE_COLOR : 6;
// Alternar color cada ITEMS_COLOR_BLINK_DURATION
if (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) {
items_color_ = 14;
} else {
items_color_ = 6;
}
} }
// Devuelve la cantidad de minutos de juego transcurridos // Devuelve la cantidad de minutos de juego transcurridos
@@ -126,56 +80,80 @@ auto Scoreboard::getMinutes() -> int {
return getTime().minutes; return getTime().minutes;
} }
// Dibuja los elementos del marcador en la textura // Dibuja los elementos del marcador en la surface
void Scoreboard::fillTexture() { void Scoreboard::fillTexture() {
// Empieza a dibujar en la textura auto previous_renderer = Screen::get()->getRendererSurface();
auto previuos_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(surface_); Screen::get()->setRendererSurface(surface_);
// Limpia la textura
surface_->clear(0); surface_->clear(0);
// Dibuja las vidas auto text = Resource::Cache::get()->getText("8bithud");
const int WALK_FRAMES = player_sprite_->getCurrentAnimationSize(); const int CANVAS_W = static_cast<int>(Options::game.width);
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % (WALK_FRAMES * 2); const std::string SEP = " - ";
const int FRAME = DESP % WALK_FRAMES; const int MONO_W = 7; // Ancho fijo por carácter monoespaciado (dígitos + separador)
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));
}
// 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) { if (data_->music) {
const Uint8 C = data_->color; indicators.push_back(Locale::get()->get("scoreboard.music_on"));
SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
item_surface_->renderWithColorReplace(MUSIC_ICON_X, LINE2_Y, 1, C, &clip);
} }
// 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) { 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) { 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 if (!indicators.empty()) {
Screen::get()->setRendererSurface(previuos_renderer); 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 <SDL3/SDL.h>
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string, basic_string #include <string> // Para string
#include <utility> #include <utility>
#include <vector> // Para vector
class AnimatedSprite; // lines 10-10 class Surface;
class Surface; // lines 11-11
class Scoreboard { class Scoreboard {
public: public:
@@ -28,58 +27,43 @@ class Scoreboard {
void render(); // Pinta el objeto en pantalla void render(); // Pinta el objeto en pantalla
void update(float delta_time); // Actualiza las variables del objeto void update(float delta_time); // Actualiza las variables del objeto
void setPaused(bool value); // Pone el marcador en modo pausa 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 auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
private: private:
// Tipos anidados // Tipos anidados
struct ClockData { struct ClockData {
int hours{0}; // Horas transcurridas int hours{0};
int minutes{0}; // Minutos transcurridos int minutes{0};
int seconds{0}; // Segundos transcurridos int seconds{0};
std::string separator{":"}; // Separador para mostrar el tiempo std::string separator{":"};
}; };
// Constantes de tiempo // 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 ITEMS_COLOR_BLINK_DURATION = 0.333F;
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
// Posición de los elementos del marcador (en pixels, Tile::SIZE = 8) // Posición de los elementos (2 líneas centradas verticalmente en surface de 24px)
static constexpr int LINE1_Y = 8; // Fila superior (1 * Tile::SIZE) static constexpr int LINE1_Y = 5;
static constexpr int LINE2_Y = 24; // Fila inferior (3 * Tile::SIZE) static constexpr int LINE2_Y = 13;
static constexpr int ITEMS_LABEL_X = 8; // "TRESORS PILLATS" / "ITEMS COLLECTED"
static constexpr int ITEMS_VALUE_X = 136; // Valor numérico de items // Colores
static constexpr int TIME_LABEL_X = 160; // "HORA" / "TIME" static constexpr Uint8 LABEL_COLOR = 11;
static constexpr int TIME_VALUE_X = 208; // Valor numérico del tiempo static constexpr Uint8 VALUE_COLOR = 9;
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
// Métodos privados // Métodos privados
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida auto getTime() -> ClockData;
void updateItemsColor(float delta_time); // Actualiza el color de la cantidad de items recogidos void updateItemsColor(float delta_time);
void fillTexture(); // Dibuja los elementos del marcador en la surface void fillTexture();
// Objetos y punteros // Objetos y punteros
std::shared_ptr<AnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador std::shared_ptr<Data> data_;
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador std::shared_ptr<Surface> surface_;
std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador
// Variables de estado // Variables de estado
std::vector<Uint8> color_; // Vector con los colores del objeto bool is_paused_{false};
bool is_paused_{false}; // Indica si el marcador esta en modo pausa Uint32 paused_time_{0};
Uint32 paused_time_{0}; // Milisegundos que ha estado el marcador en pausa Uint32 paused_time_elapsed_{0};
Uint32 paused_time_elapsed_{0}; // Tiempo acumulado en pausa ClockData clock_{};
ClockData clock_{}; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida Uint8 items_color_{VALUE_COLOR};
Uint8 items_color_{0}; // Color de la cantidad de items recogidos SDL_FRect surface_dest_{};
SDL_FRect surface_dest_{}; // Rectangulo donde dibujar la surface del marcador float items_color_timer_{0.0F};
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
float items_color_timer_{0.0F}; // Timer para parpadeo de color de items
}; };

View File

@@ -85,7 +85,6 @@ Game::Game(Mode mode)
GameControl::change_player_skin = [this](const std::string& skin_name) -> void { GameControl::change_player_skin = [this](const std::string& skin_name) -> void {
Options::game.player_skin = skin_name; Options::game.player_skin = skin_name;
player_->setSkin(skin_name); player_->setSkin(skin_name);
scoreboard_->refreshPlayerSkin();
}; };
GameControl::change_player_color = [this](int color) -> void { GameControl::change_player_color = [this](int color) -> void {
Options::game.player_color = color; Options::game.player_color = color;
@@ -548,10 +547,6 @@ void Game::renderDebugInfo() {
auto surface = Screen::get()->getRendererSurface(); auto surface = Screen::get()->getRendererSurface();
// Borra el marcador
SDL_FRect rect = {.x = 0, .y = 18 * Tile::SIZE, .w = PlayArea::WIDTH, .h = GameCanvas::HEIGHT - PlayArea::HEIGHT};
surface->fillRect(&rect, 0);
// Pinta la rejilla // Pinta la rejilla
/*for (int i = 0; i < PlayArea::BOTTOM; i += 8) /*for (int i = 0; i < PlayArea::BOTTOM; i += 8)
{ {

View File

@@ -144,6 +144,13 @@ void Console::redrawText() {
SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_}; SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_};
surface_->drawRectBorder(&rect, BORDER_COLOR); surface_->drawRectBorder(&rect, BORDER_COLOR);
// La surface de la fuente tiene transparent_color_=255 por defecto,
// pero sus píxeles de fondo son color 0. Cambiarlo temporalmente a 0
// para que no pinte el fondo negro de los glyphs sobre la consola.
auto* font_surface = text_->getSprite()->getSurface().get();
const Uint8 PREV_TRANSPARENT = font_surface->getTransparentColor();
font_surface->setTransparentColor(0);
// Líneas de mensaje con efecto typewriter (solo muestra los primeros typewriter_chars_) // Líneas de mensaje con efecto typewriter (solo muestra los primeros typewriter_chars_)
int y_pos = PADDING_IN_V; int y_pos = PADDING_IN_V;
int remaining = typewriter_chars_; int remaining = typewriter_chars_;
@@ -160,6 +167,9 @@ void Console::redrawText() {
const std::string INPUT_STR = prompt_ + input_line_ + (SHOW_CURSOR ? "_" : ""); const std::string INPUT_STR = prompt_ + input_line_ + (SHOW_CURSOR ? "_" : "");
text_->writeColored(PADDING_IN_H, y_pos, INPUT_STR, BORDER_COLOR); text_->writeColored(PADDING_IN_H, y_pos, INPUT_STR, BORDER_COLOR);
// Restaurar transparent_color_ original de la fuente
font_surface->setTransparentColor(PREV_TRANSPARENT);
Screen::get()->setRendererSurface(previous_renderer); Screen::get()->setRendererSurface(previous_renderer);
} }

View File

@@ -51,7 +51,7 @@ class Console {
}; };
// Constantes visuales // Constantes visuales
static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK static constexpr Uint8 BG_COLOR = 255; // Transparente (sin fondo)
static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN
static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN
static constexpr float SLIDE_SPEED = 180.0F; static constexpr float SLIDE_SPEED = 180.0F;