animacio al pixel del carrusel feta, falla el color que no transiciona
This commit is contained in:
@@ -20,10 +20,12 @@ class EnterName {
|
|||||||
void addCharacter(); // Añade el carácter seleccionado al nombre
|
void addCharacter(); // Añade el carácter seleccionado al nombre
|
||||||
void removeLastCharacter(); // Elimina el último carácter del nombre
|
void removeLastCharacter(); // Elimina el último carácter del nombre
|
||||||
|
|
||||||
auto getFinalName() -> std::string; // Obtiene el nombre final (o aleatorio si vacío)
|
auto getFinalName() -> std::string; // Obtiene el nombre final (o aleatorio si vacío)
|
||||||
[[nodiscard]] auto getCurrentName() const -> std::string { return name_; } // Obtiene el nombre actual en proceso
|
[[nodiscard]] auto getCurrentName() const -> std::string { return name_; } // Obtiene el nombre actual en proceso
|
||||||
[[nodiscard]] auto getSelectedCharacter(int offset = 0) const -> std::string; // Devuelve el carácter seleccionado con offset relativo
|
[[nodiscard]] auto getSelectedCharacter(int offset = 0) const -> std::string; // Devuelve el carácter seleccionado con offset relativo
|
||||||
[[nodiscard]] auto getCarousel(int size) const -> std::string; // Devuelve el carrusel de caracteres (size debe ser impar)
|
[[nodiscard]] auto getCarousel(int size) const -> std::string; // Devuelve el carrusel de caracteres (size debe ser impar)
|
||||||
|
[[nodiscard]] auto getSelectedIndex() const -> int { return selected_index_; } // Obtiene el índice del carácter seleccionado
|
||||||
|
[[nodiscard]] auto getCharacterList() const -> const std::string& { return character_list_; } // Obtiene la lista completa de caracteres
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Variables de estado ---
|
// --- Variables de estado ---
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ void Player::updateScoreboard() {
|
|||||||
case State::ENTERING_NAME_GAME_COMPLETED: {
|
case State::ENTERING_NAME_GAME_COMPLETED: {
|
||||||
Scoreboard::get()->setEnterName(scoreboard_panel_, enter_name_->getCurrentName());
|
Scoreboard::get()->setEnterName(scoreboard_panel_, enter_name_->getCurrentName());
|
||||||
Scoreboard::get()->setCharacterSelected(scoreboard_panel_, enter_name_->getSelectedCharacter());
|
Scoreboard::get()->setCharacterSelected(scoreboard_panel_, enter_name_->getSelectedCharacter());
|
||||||
Scoreboard::get()->setCarousel(scoreboard_panel_, enter_name_->getCarousel(7));
|
Scoreboard::get()->setCarouselAnimation(scoreboard_panel_, enter_name_->getSelectedIndex(), enter_name_.get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ Scoreboard::Scoreboard()
|
|||||||
score_.at(i) = 0;
|
score_.at(i) = 0;
|
||||||
mult_.at(i) = 0;
|
mult_.at(i) = 0;
|
||||||
continue_counter_.at(i) = 0;
|
continue_counter_.at(i) = 0;
|
||||||
|
carousel_prev_index_.at(i) = -1; // Inicializar a -1 para detectar primera inicialización
|
||||||
|
enter_name_ref_.at(i) = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
panel_.at(static_cast<size_t>(Id::LEFT)).mode = Mode::SCORE;
|
panel_.at(static_cast<size_t>(Id::LEFT)).mode = Mode::SCORE;
|
||||||
@@ -90,38 +92,52 @@ Scoreboard::~Scoreboard() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establece el carrusel y detecta cambios para iniciar animación
|
// Configura la animación del carrusel
|
||||||
void Scoreboard::setCarousel(Id id, const std::string& carousel) {
|
void Scoreboard::setCarouselAnimation(Id id, int selected_index, EnterName* enter_name_ptr) {
|
||||||
size_t idx = static_cast<size_t>(id);
|
size_t idx = static_cast<size_t>(id);
|
||||||
|
|
||||||
if (carousel.empty()) {
|
// Guardar referencia a EnterName
|
||||||
carousel_.at(idx) = carousel;
|
enter_name_ref_.at(idx) = enter_name_ptr;
|
||||||
|
|
||||||
|
if (!enter_name_ptr || selected_index < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcular el índice central del nuevo carrusel
|
// Primera inicialización: posicionar directamente sin animar
|
||||||
int new_center_index = carousel.size() / 2;
|
if (carousel_prev_index_.at(idx) == -1) {
|
||||||
|
carousel_position_.at(idx) = static_cast<float>(selected_index);
|
||||||
// Si es la primera vez o cambió el índice, establecer nuevo target
|
carousel_target_.at(idx) = static_cast<float>(selected_index);
|
||||||
if (carousel_.at(idx).empty()) {
|
carousel_prev_index_.at(idx) = selected_index;
|
||||||
// Primera inicialización: posicionar directamente sin animar
|
|
||||||
carousel_position_.at(idx) = static_cast<float>(new_center_index);
|
|
||||||
carousel_target_.at(idx) = static_cast<float>(new_center_index);
|
|
||||||
carousel_prev_index_.at(idx) = new_center_index;
|
|
||||||
} else {
|
} else {
|
||||||
// Calcular índice central del carrusel anterior
|
// Detectar cambio en el índice del carácter seleccionado
|
||||||
int prev_center_index = carousel_.at(idx).size() / 2;
|
int prev_index = carousel_prev_index_.at(idx);
|
||||||
|
|
||||||
// Detectar si cambió (LEFT o RIGHT fue presionado)
|
if (selected_index != prev_index) {
|
||||||
if (new_center_index != prev_center_index) {
|
// Calcular dirección del movimiento
|
||||||
// Establecer nuevo target (la animación se hará en updateCarouselAnimation)
|
int direction = selected_index - prev_index;
|
||||||
carousel_target_.at(idx) = static_cast<float>(new_center_index);
|
|
||||||
|
// Obtener tamaño de la lista para manejar wrap-around
|
||||||
|
const int LIST_SIZE = enter_name_ptr->getCharacterList().size();
|
||||||
|
|
||||||
|
// 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 a -1 o +1
|
||||||
|
direction = (direction > 0) ? 1 : ((direction < 0) ? -1 : 0);
|
||||||
|
|
||||||
|
if (direction != 0) {
|
||||||
|
// Actualizar target con movimiento relativo
|
||||||
|
carousel_target_.at(idx) = carousel_position_.at(idx) + static_cast<float>(direction);
|
||||||
|
|
||||||
|
// Guardar nuevo índice
|
||||||
|
carousel_prev_index_.at(idx) = selected_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
carousel_prev_index_.at(idx) = new_center_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
carousel_.at(idx) = carousel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transforma un valor numérico en una cadena de 7 cifras
|
// Transforma un valor numérico en una cadena de 7 cifras
|
||||||
@@ -498,8 +514,15 @@ void Scoreboard::renderSeparator() {
|
|||||||
|
|
||||||
// Pinta el carrusel de caracteres con efecto de color LERP y animación suave
|
// Pinta el carrusel de caracteres con efecto de color LERP y animación suave
|
||||||
void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
||||||
const std::string& carousel = carousel_.at(panel_index);
|
// Obtener referencia a EnterName
|
||||||
if (carousel.empty()) {
|
EnterName* enter_name = enter_name_ref_.at(panel_index);
|
||||||
|
if (!enter_name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener la lista completa de caracteres
|
||||||
|
const std::string& char_list = enter_name->getCharacterList();
|
||||||
|
if (char_list.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,11 +533,11 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
|||||||
constexpr int VISIBLE_LETTERS = 9;
|
constexpr int VISIBLE_LETTERS = 9;
|
||||||
constexpr int HALF_VISIBLE = VISIBLE_LETTERS / 2; // 4
|
constexpr int HALF_VISIBLE = VISIBLE_LETTERS / 2; // 4
|
||||||
|
|
||||||
// Posición flotante actual del carrusel
|
// Posición flotante actual del carrusel (índice en character_list_)
|
||||||
const float carousel_pos = carousel_position_.at(panel_index);
|
const float carousel_pos = carousel_position_.at(panel_index);
|
||||||
|
|
||||||
// Calcular ancho promedio de una letra (asumimos ancho uniforme para simplificar)
|
// Calcular ancho promedio de una letra (asumimos ancho uniforme)
|
||||||
std::string sample_char(1, carousel[carousel.size() / 2]);
|
std::string sample_char(1, char_list[0]);
|
||||||
const int AVG_CHAR_WIDTH = text_->length(sample_char, 1);
|
const int AVG_CHAR_WIDTH = text_->length(sample_char, 1);
|
||||||
const int CHAR_STEP = AVG_CHAR_WIDTH + EXTRA_SPACING;
|
const int CHAR_STEP = AVG_CHAR_WIDTH + EXTRA_SPACING;
|
||||||
|
|
||||||
@@ -522,28 +545,29 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
|||||||
const float fractional_offset = carousel_pos - std::floor(carousel_pos);
|
const float fractional_offset = carousel_pos - std::floor(carousel_pos);
|
||||||
const int pixel_offset = static_cast<int>(fractional_offset * CHAR_STEP);
|
const int pixel_offset = static_cast<int>(fractional_offset * CHAR_STEP);
|
||||||
|
|
||||||
// Índice base (centro del carrusel)
|
// Índice base en character_list_ (centro del carrusel)
|
||||||
const int base_index = static_cast<int>(std::floor(carousel_pos));
|
const int base_index = static_cast<int>(std::floor(carousel_pos));
|
||||||
|
const int char_list_size = static_cast<int>(char_list.size());
|
||||||
|
|
||||||
// Calcular posición X inicial (centrar el conjunto de 9 letras)
|
// Calcular posición X inicial (centrar el conjunto de 9 letras)
|
||||||
int start_x = center_x - (HALF_VISIBLE * CHAR_STEP) - (AVG_CHAR_WIDTH / 2) - pixel_offset;
|
int start_x = center_x - (HALF_VISIBLE * CHAR_STEP) - (AVG_CHAR_WIDTH / 2) - pixel_offset;
|
||||||
|
|
||||||
|
// Detectar si el carrusel está en movimiento
|
||||||
|
const bool is_animating = std::abs(carousel_pos - carousel_target_.at(panel_index)) > 0.01f;
|
||||||
|
|
||||||
// Renderizar las 9 letras visibles
|
// Renderizar las 9 letras visibles
|
||||||
for (int i = -HALF_VISIBLE; i <= HALF_VISIBLE; ++i) {
|
for (int i = -HALF_VISIBLE; i <= HALF_VISIBLE; ++i) {
|
||||||
// Índice real en la lista de caracteres (con wrap-around circular)
|
// Índice real en character_list_ (con wrap-around circular)
|
||||||
int char_index = base_index + i;
|
int char_index = base_index + i;
|
||||||
const int carousel_size = static_cast<int>(carousel.size());
|
|
||||||
|
|
||||||
// Wrap-around circular
|
// Wrap-around circular
|
||||||
while (char_index < 0) {
|
char_index = char_index % char_list_size;
|
||||||
char_index += carousel_size;
|
if (char_index < 0) {
|
||||||
}
|
char_index += char_list_size;
|
||||||
while (char_index >= carousel_size) {
|
|
||||||
char_index -= carousel_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener el carácter
|
// Obtener el carácter directamente de character_list_
|
||||||
std::string single_char(1, carousel[char_index]);
|
std::string single_char(1, char_list[char_index]);
|
||||||
|
|
||||||
// Calcular distancia flotante al centro visual
|
// Calcular distancia flotante al centro visual
|
||||||
const float distance_from_center = std::abs(static_cast<float>(i) + fractional_offset);
|
const float distance_from_center = std::abs(static_cast<float>(i) + fractional_offset);
|
||||||
@@ -551,13 +575,22 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
|||||||
// Calcular color con LERP dinámico
|
// Calcular color con LERP dinámico
|
||||||
Color letter_color;
|
Color letter_color;
|
||||||
|
|
||||||
if (distance_from_center < 0.5f) {
|
if (distance_from_center < 0.5f && !is_animating) {
|
||||||
// Letra central: animated_color_
|
// Letra central Y carrusel quieto: animated_color_
|
||||||
letter_color = animated_color_;
|
letter_color = animated_color_;
|
||||||
} else {
|
} else {
|
||||||
// Letras laterales: LERP desde text_color1_ hacia color_
|
// Todas las demás letras O carrusel en movimiento: LERP
|
||||||
// Factor: 0.0 cerca del centro, 0.85 en los extremos (85% fade)
|
float base_lerp;
|
||||||
const float LERP_FACTOR = std::min((distance_from_center - 0.5f) / (HALF_VISIBLE - 0.5f), 1.0f) * 0.85f;
|
if (distance_from_center < 0.5f) {
|
||||||
|
// Letra muy cerca del centro durante animación: 0% (color brillante)
|
||||||
|
base_lerp = 0.0f;
|
||||||
|
} else {
|
||||||
|
// Letras alejadas: lerp proporcional a la distancia
|
||||||
|
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);
|
letter_color = text_color1_.LERP(color_, LERP_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <string> // Para string, basic_string
|
#include <string> // Para string, basic_string
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class EnterName;
|
||||||
|
|
||||||
#include "color.h" // Para Color
|
#include "color.h" // Para Color
|
||||||
|
|
||||||
class Sprite;
|
class Sprite;
|
||||||
@@ -65,7 +68,7 @@ class Scoreboard {
|
|||||||
void setPower(float power) { power_ = power; }
|
void setPower(float power) { power_ = power; }
|
||||||
void setEnterName(Id id, const std::string& enter_name) { enter_name_.at(static_cast<size_t>(id)) = enter_name; }
|
void setEnterName(Id id, const std::string& enter_name) { enter_name_.at(static_cast<size_t>(id)) = enter_name; }
|
||||||
void setCharacterSelected(Id id, const std::string& character_selected) { character_selected_.at(static_cast<size_t>(id)) = character_selected; }
|
void setCharacterSelected(Id id, const std::string& character_selected) { character_selected_.at(static_cast<size_t>(id)) = character_selected; }
|
||||||
void setCarousel(Id id, const std::string& carousel); // Implementación en .cpp para detectar cambios
|
void setCarouselAnimation(Id id, int selected_index, EnterName* enter_name_ptr); // Configura la animación del carrusel
|
||||||
void setScore(Id id, int score) { score_.at(static_cast<size_t>(id)) = score; }
|
void setScore(Id id, int score) { score_.at(static_cast<size_t>(id)) = score; }
|
||||||
void setSelectorPos(Id id, int pos) { selector_pos_.at(static_cast<size_t>(id)) = pos; }
|
void setSelectorPos(Id id, int pos) { selector_pos_.at(static_cast<size_t>(id)) = pos; }
|
||||||
void setStage(int stage) { stage_ = stage; }
|
void setStage(int stage) { stage_ = stage; }
|
||||||
@@ -83,10 +86,10 @@ class Scoreboard {
|
|||||||
std::array<std::string, static_cast<int>(Id::SIZE)> name_ = {}; // Nombre de cada jugador
|
std::array<std::string, static_cast<int>(Id::SIZE)> name_ = {}; // Nombre de cada jugador
|
||||||
std::array<std::string, static_cast<int>(Id::SIZE)> enter_name_ = {}; // Nombre introducido para la tabla de records
|
std::array<std::string, static_cast<int>(Id::SIZE)> enter_name_ = {}; // Nombre introducido para la tabla de records
|
||||||
std::array<std::string, static_cast<int>(Id::SIZE)> character_selected_ = {}; // Caracter seleccionado
|
std::array<std::string, static_cast<int>(Id::SIZE)> character_selected_ = {}; // Caracter seleccionado
|
||||||
std::array<std::string, static_cast<int>(Id::SIZE)> carousel_ = {}; // Caracter seleccionado
|
std::array<EnterName*, static_cast<int>(Id::SIZE)> enter_name_ref_ = {}; // Referencias a EnterName para obtener character_list_
|
||||||
std::array<float, static_cast<int>(Id::SIZE)> carousel_position_ = {}; // Posición actual del carrusel (animación suave)
|
std::array<float, static_cast<int>(Id::SIZE)> carousel_position_ = {}; // Posición actual del carrusel (índice en character_list_)
|
||||||
std::array<float, static_cast<int>(Id::SIZE)> carousel_target_ = {}; // Posición objetivo del carrusel
|
std::array<float, static_cast<int>(Id::SIZE)> carousel_target_ = {}; // Posición objetivo del carrusel
|
||||||
std::array<int, static_cast<int>(Id::SIZE)> carousel_prev_index_ = {}; // Índice previo para detectar cambios
|
std::array<int, static_cast<int>(Id::SIZE)> carousel_prev_index_ = {}; // Índice previo para detectar cambios
|
||||||
std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador
|
std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador
|
||||||
Colors::Cycle name_color_cycle_; // Ciclo de colores para destacar el nombre una vez introducido
|
Colors::Cycle name_color_cycle_; // Ciclo de colores para destacar el nombre una vez introducido
|
||||||
Color animated_color_; // Color actual animado (ciclo automático cada 100ms)
|
Color animated_color_; // Color actual animado (ciclo automático cada 100ms)
|
||||||
|
|||||||
Reference in New Issue
Block a user