diff --git a/data/font/8bithud.png b/data/font/8bithud.png index 2ac5e4c..d297771 100644 Binary files a/data/font/8bithud.png and b/data/font/8bithud.png differ diff --git a/data/font/8bithud.txt b/data/font/8bithud.txt index 48e961f..7a93038 100644 --- a/data/font/8bithud.txt +++ b/data/font/8bithud.txt @@ -185,7 +185,7 @@ # 122 z 5 # 123 { -3 +7 # 124 | 2 # 125 } diff --git a/source/director.cpp b/source/director.cpp index a4a282c..79f7560 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -44,7 +44,7 @@ Director::Director(int argc, std::span argv) { Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #elif _DEBUG - Section::name = Section::Name::HI_SCORE_TABLE; + Section::name = Section::Name::GAME; Section::options = Section::Options::GAME_PLAY_1P; #else // NORMAL GAME Section::name = Section::Name::LOGO; diff --git a/source/enter_name.cpp b/source/enter_name.cpp index 2d34615..da37157 100644 --- a/source/enter_name.cpp +++ b/source/enter_name.cpp @@ -6,7 +6,7 @@ // Constructor EnterName::EnterName() - : character_list_("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.") {} + : character_list_("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{") {} // Inicializa el objeto void EnterName::init(const std::string& name) { diff --git a/source/scoreboard.cpp b/source/scoreboard.cpp index 2bd37a7..a2b367c 100644 --- a/source/scoreboard.cpp +++ b/source/scoreboard.cpp @@ -5,7 +5,8 @@ #include // Para max #include // Para roundf #include // Para operator<<, setfill, setw -#include // Para basic_ostream, basic_ostringstream, basic_ostream::operator<<, ostringstream +#include +#include // Para basic_ostream, basic_ostringstream, basic_ostream::operator<<, ostringstream #include "color.hpp" #include "enter_name.hpp" // Para NAME_SIZE @@ -94,6 +95,7 @@ Scoreboard::~Scoreboard() { } } +// Configura la animación del carrusel // Configura la animación del carrusel void Scoreboard::setCarouselAnimation(Id id, int selected_index, EnterName* enter_name_ptr) { auto idx = static_cast(id); @@ -108,40 +110,52 @@ void Scoreboard::setCarouselAnimation(Id id, int selected_index, EnterName* ente // Primera inicialización: posicionar directamente sin animar if (carousel_prev_index_.at(idx) == -1) { carousel_position_.at(idx) = static_cast(selected_index); - carousel_target_.at(idx) = static_cast(selected_index); + carousel_target_.at(idx) = static_cast(selected_index); carousel_prev_index_.at(idx) = selected_index; - } else { - // Detectar cambio en el índice del carácter seleccionado - int prev_index = carousel_prev_index_.at(idx); + return; + } - if (selected_index != prev_index) { - // Calcular dirección del movimiento - int direction = selected_index - prev_index; + int prev_index = carousel_prev_index_.at(idx); - // Obtener tamaño de la lista para manejar wrap-around - const int LIST_SIZE = enter_name_ptr->getCharacterList().size(); + // Si el índice seleccionado no cambia, no hay nada que hacer + if (selected_index == prev_index) { + return; + } - // Manejar wrap-around circular - if (direction > LIST_SIZE / 2) { - direction = -(LIST_SIZE - direction); // Wrap backward (ej: Z → A) - } else if (direction < -LIST_SIZE / 2) { - direction = LIST_SIZE + direction; // Wrap forward (ej: A → Z) - } + // 🚫 BLOQUEO: si todavía hay una animación en curso, ignoramos el nuevo movimiento + if (std::abs(carousel_position_.at(idx) - carousel_target_.at(idx)) > 0.01f) { + return; // Aún animando: no aceptar nuevo target hasta terminar + } - // Normalizar a -1 o +1 - direction = (direction > 0) ? 1 : ((direction < 0) ? -1 : 0); + // ---- Animación completada → procesar el nuevo movimiento ---- + int direction = selected_index - prev_index; - if (direction != 0) { - // Actualizar target con movimiento relativo - carousel_target_.at(idx) = carousel_position_.at(idx) + static_cast(direction); + // Obtener tamaño de la lista para manejar wrap-around + const int LIST_SIZE = static_cast(enter_name_ptr->getCharacterList().size()); - // Guardar nuevo índice - carousel_prev_index_.at(idx) = selected_index; - } - } + // Manejar wrap-around circular + if (direction > LIST_SIZE / 2) { + direction = -(LIST_SIZE - direction); // Wrap backward (ej: Z → A) + } else if (direction < -LIST_SIZE / 2) { + direction = LIST_SIZE + direction; // Wrap forward (ej: A → Z) + } + + // Normalizar dirección a -1 o +1 + direction = (direction > 0) ? 1 : ((direction < 0) ? -1 : 0); + + if (direction != 0) { + // Asegurar que partimos de una posición alineada + carousel_position_.at(idx) = std::round(carousel_position_.at(idx)); + + // Actualizar el nuevo target relativo + carousel_target_.at(idx) = carousel_position_.at(idx) + static_cast(direction); + + // Guardar el nuevo índice seleccionado + carousel_prev_index_.at(idx) = selected_index; } } + // Establece el modo del panel y gestiona transiciones void Scoreboard::setMode(Id id, Mode mode) { auto idx = static_cast(id); @@ -242,6 +256,13 @@ void Scoreboard::updateCarouselAnimation(float delta_time) { carousel_position_.at(i) = carousel_target_.at(i); } } + + // Después del bloque principal en updateCarouselAnimation() + /*for (size_t i = 0; i < carousel_position_.size(); ++i) { + if (std::abs(carousel_position_.at(i) - carousel_target_.at(i)) <= 0.01F) { + carousel_position_.at(i) = std::round(carousel_target_.at(i)); // <-- redondea + } + }*/ } // Actualiza las animaciones de deslizamiento de texto @@ -662,73 +683,72 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) { return; } - // Espacio extra entre letras + // --- Parámetros del carrusel --- constexpr int EXTRA_SPACING = 2; + constexpr int HALF_VISIBLE = CAROUSEL_VISIBLE_LETTERS / 2; // 4 letras a cada lado - // Carrusel extendido: usar constante de clase - constexpr int HALF_VISIBLE = CAROUSEL_VISIBLE_LETTERS / 2; // 4 - - // Posición flotante actual del carrusel (índice en character_list_) - const float CAROUSEL_POS = carousel_position_.at(panel_index); - - // Calcular ancho promedio de una letra (asumimos ancho uniforme) - std::string sample_char(1, char_list[0]); - const int AVG_CHAR_WIDTH = text_->length(sample_char, 1); - const int CHAR_STEP = AVG_CHAR_WIDTH + EXTRA_SPACING; - - // Calcular offset de píxeles basado en la parte fraccionaria de carousel_pos - const float FRACTIONAL_OFFSET = CAROUSEL_POS - std::floor(CAROUSEL_POS); - const int PIXEL_OFFSET = static_cast(FRACTIONAL_OFFSET * CHAR_STEP); - - // Índice base en character_list_ (centro del carrusel) - const int BASE_INDEX = static_cast(std::floor(CAROUSEL_POS)); + // Posición flotante actual del carrusel (índice en la lista de caracteres) + float CAROUSEL_POS = carousel_position_.at(panel_index); const int CHAR_LIST_SIZE = static_cast(char_list.size()); - // Calcular posición X inicial (centrar el conjunto de 9 letras) + // Calcular ancho promedio de una letra (asumimos ancho uniforme) + const int AVG_CHAR_WIDTH = text_->getCharacterSize(); + const int CHAR_STEP = AVG_CHAR_WIDTH + EXTRA_SPACING; + + // --- Corrección visual de residuales flotantes (evita “baile”) --- + float frac = CAROUSEL_POS - std::floor(CAROUSEL_POS); + if (frac > 0.999f || frac < 0.001f) { + CAROUSEL_POS = std::round(CAROUSEL_POS); + frac = 0.0f; + } + + const float FRACTIONAL_OFFSET = frac; + const int PIXEL_OFFSET = static_cast(FRACTIONAL_OFFSET * CHAR_STEP + 0.5f); + + // Índice base en la lista de caracteres (posición central) + const int BASE_INDEX = static_cast(std::floor(CAROUSEL_POS)); + + // Calcular posición X inicial (centrar las 9 letras visibles) int start_x = center_x - (HALF_VISIBLE * CHAR_STEP) - (AVG_CHAR_WIDTH / 2) - PIXEL_OFFSET; - // Renderizar las 9 letras visibles + // === Renderizar las letras visibles del carrusel === for (int i = -HALF_VISIBLE; i <= HALF_VISIBLE; ++i) { // Índice real en character_list_ (con wrap-around circular) int char_index = BASE_INDEX + i; - - // Wrap-around circular char_index = char_index % CHAR_LIST_SIZE; if (char_index < 0) { char_index += CHAR_LIST_SIZE; } - // Obtener el carácter directamente de character_list_ - std::string single_char(1, char_list[char_index]); + // --- Calcular distancia circular correcta (corregido el bug de wrap) --- + float normalized_pos = std::fmod(CAROUSEL_POS, static_cast(CHAR_LIST_SIZE)); + if (normalized_pos < 0.0f) normalized_pos += static_cast(CHAR_LIST_SIZE); - // Calcular distancia flotante al centro visual basada en posición real del carácter - float distance_from_center = std::abs(static_cast(char_index) - CAROUSEL_POS); + float diff = std::abs(static_cast(char_index) - normalized_pos); + if (diff > static_cast(CHAR_LIST_SIZE) / 2.0f) + diff = static_cast(CHAR_LIST_SIZE) - diff; - // Manejar wrap-around circular: elegir el camino más corto - if (distance_from_center > static_cast(CHAR_LIST_SIZE) / 2.0F) { - distance_from_center = static_cast(CHAR_LIST_SIZE) - distance_from_center; - } + const float distance_from_center = diff; - // Calcular color con LERP dinámico continuo + // --- Seleccionar color con LERP según la distancia --- Color letter_color; - if (distance_from_center < 0.5F) { - // Letra cerca del centro: LERP hacia animated_color_ - // distance_from_center va de 0.0 (centro exacto) a 0.5 (borde) + // Letra central → transiciona hacia animated_color_ float lerp_to_animated = distance_from_center / 0.5F; // 0.0 a 1.0 letter_color = animated_color_.LERP(text_color1_, lerp_to_animated); } else { - // Letras alejadas: LERP hacia color_ (fade out) + // Letras alejadas → degradan hacia color_ base float base_lerp = (distance_from_center - 0.5F) / (HALF_VISIBLE - 0.5F); base_lerp = std::min(base_lerp, 1.0F); const float LERP_FACTOR = base_lerp * 0.85F; letter_color = text_color1_.LERP(color_, LERP_FACTOR); } - // Calcular posición X de esta letra + // Calcular posición X de la letra const int LETTER_X = start_x + ((i + HALF_VISIBLE) * CHAR_STEP); - // Pintar la letra + // Renderizar la letra + std::string single_char(1, char_list[char_index]); text_->writeDX(Text::COLOR, LETTER_X, y, single_char, 1, letter_color); } -} \ No newline at end of file +}