From bb132aade26bffc141e5c49c3c9d7c8b7f4865c7 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 22 Oct 2025 15:05:57 +0200 Subject: [PATCH] =?UTF-8?q?afegit=20caracter=20de=20acabar=20de=20posar=20?= =?UTF-8?q?el=20nom=20(no=20en=20us=20encara)=20corregida=20la=20logica=20?= =?UTF-8?q?de=20animacio=20i=20despla=C3=A7ament=20del=20carrusel=20de=20p?= =?UTF-8?q?osar=20nom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/font/8bithud.png | Bin 1094 -> 1088 bytes data/font/8bithud.txt | 2 +- source/director.cpp | 2 +- source/enter_name.cpp | 2 +- source/scoreboard.cpp | 146 ++++++++++++++++++++++++------------------ 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/data/font/8bithud.png b/data/font/8bithud.png index 2ac5e4c8d74520242b2fb7a2bcf709bd8fc9a0e7..d2977710ed20faaa9e0e8c704f6820bdc0b65bb0 100644 GIT binary patch delta 1055 zcmV+)1mOF|2*3!CFn(aph+zCuJfNddfb2@!Cf9wes_K zubnGzg7N}yVshj}X=USY$8j7|M*D6p#JB*mEla1FpbhT*{(lL|3+yc}%d8WuwYPF{ zW&2uR$Tcx#SGEvu3VOXhk7i{u zV?>tAxs{JXt|+K;Fqi z8;0FbtbWn*=zoUJmRHGcglDDli5J)~1D+uh-8j*)M*C;`Vf66U$FiI!^a-xw4a76) zvn)XMgjw}xSfInWpxKDShc?K*+6Vmapx_a02qum5`k+s6)wftXe|Ec7xoG_vK9@1$ zW1b(W+ceFcp^o?Lzy{^XO#7aRpP7fV{aY_&(de4V`+qgvtoEMKL|pm;Z7|y4yeC3t zf+Fcg##gPnh=`8E!;7{po}L4j3Ng{(*1u1)PA-9)z_?<#of**8ZGh`*nw4( zw-pBCG3!Ogng{kEWU&qoV&BNcd;G#E5>eo8%pPB4Gen<4H^v7`MOH1KWgjKa6DT|f8hi#gs$U~YoCe^WWF)62&$?_HTE&aW6Hceyl zP?Y9n%9-)GuSuhAkN5W4#Bte8L>{k zEVE=zGMn^c@4+)K5@eKZ$=wBX4^go`p#`p-Vt+8LLM&vOKZ~V!w4cb`?21Lso?r=Mfg*aL@xl{)mmtVG zLGq$Plkw`ya!*D>>p#L+&sxm8tWnc6P4kBOz#mC7q;JyNd+QMRkZPX$tvs2XKW2Up zC;n7@>wlp^e!dH@D0)VEv2p@t<(adi}m=oD1`o5?qvGcH|X&9O- Z@B;_N$Tspn>(^PhRShtQtAEydS|_uiL-+b1vW>=D^6`CS z=bJA<`G7B%=grX@Wy$1s$8j85$NKCYgggLk%kya^=z>Szzkh@B0Y`_+vMPctdpi$T z+qdRIrHPS!bB1_wFmhIYZ>3o&i!MZVBbd#LbgB_tJv=lXMsU>ul%lIxDLUgXss(-(uavAff1^8voP&YYN+#zaStx9O3d*YH^5SvmS#wZB{LWhEr9a%UBz z1x1mEE)092SbzVr^6Z74l~d3^clbPiD>I&9Axbt^xl$sCh&ef_cV8bI=i7tu5ZoUv0OlmmR;N z<}zt~9HQ3kz-*ddh6?Z1jSYGyGxnntzw#Z<&ad?|_J1YXp7q)C&9iq$3f2UA0n9HU zybVBdwh7GGN8=^cCN#T_h^X84xJLzCJH&K@!(R6J;9Z7QAp6z%S2SD5{)}Ju%O&p8 zf?E)W$q@ytkOvvt(Mn zW4z~oBxj##-rCvmvvOvAR>r(b;V_)33CKZf^2`Ef##`fd_YfYkhR<}u%w@Lp1~*1Y zI?6isZVtt#{gHUluVtRjVCIs(?eD=TmCTN3Z-4kVqoZ8QE7>P?z?CRwoQoEMQur?P zGbx&vIiRfX)zY%;e>TYUI8$So#=^o%&9n1+{*TYm#q(;c_GvaqPzgF?=4zS-g1Szo zGp%&4om%z+n=Di_Dh-6RftnZTk0-O_NC%C#)*g+|`lxHPSHnHq);v-N{ylg%nF};N zGk?vFH$L)%v5&?h|Fg*b+5SxO9I$?#wc&wMd37V%`F9=Uu2Mz+!G9Ld@$5Y4356oC z%4`H{m<*Kh3#}JM@L8H5FM{OdmEW=BwLH?Xu;$Mo$9ac&mNROarfHrq|G=MlX6V{v z*?XE0)R5{s_fzj=cK?|Dl{!*x)nFvQX@BMFd(9hveV{i?I%vt?J>F{4te?-qUl+aN zd9iZ?R=qP 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 +}