treballant en la animacio alpixel del carrusel
This commit is contained in:
@@ -90,6 +90,40 @@ Scoreboard::~Scoreboard() {
|
||||
}
|
||||
}
|
||||
|
||||
// Establece el carrusel y detecta cambios para iniciar animación
|
||||
void Scoreboard::setCarousel(Id id, const std::string& carousel) {
|
||||
size_t idx = static_cast<size_t>(id);
|
||||
|
||||
if (carousel.empty()) {
|
||||
carousel_.at(idx) = carousel;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calcular el índice central del nuevo carrusel
|
||||
int new_center_index = carousel.size() / 2;
|
||||
|
||||
// Si es la primera vez o cambió el índice, establecer nuevo target
|
||||
if (carousel_.at(idx).empty()) {
|
||||
// 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 {
|
||||
// Calcular índice central del carrusel anterior
|
||||
int prev_center_index = carousel_.at(idx).size() / 2;
|
||||
|
||||
// Detectar si cambió (LEFT o RIGHT fue presionado)
|
||||
if (new_center_index != prev_center_index) {
|
||||
// Establecer nuevo target (la animación se hará en updateCarouselAnimation)
|
||||
carousel_target_.at(idx) = static_cast<float>(new_center_index);
|
||||
}
|
||||
|
||||
carousel_prev_index_.at(idx) = new_center_index;
|
||||
}
|
||||
|
||||
carousel_.at(idx) = carousel;
|
||||
}
|
||||
|
||||
// Transforma un valor numérico en una cadena de 7 cifras
|
||||
auto Scoreboard::updateScoreText(int num) -> std::string {
|
||||
std::ostringstream oss;
|
||||
@@ -120,11 +154,41 @@ void Scoreboard::updateNameColorIndex() {
|
||||
animated_color_ = name_color_cycle_.at(name_color_index_ % name_color_cycle_.size());
|
||||
}
|
||||
|
||||
// Actualiza la animación del carrusel
|
||||
void Scoreboard::updateCarouselAnimation(float deltaTime) {
|
||||
constexpr float CAROUSEL_SPEED = 8.0f; // Posiciones por segundo
|
||||
|
||||
for (size_t i = 0; i < carousel_position_.size(); ++i) {
|
||||
// Solo animar si no hemos llegado al target
|
||||
if (std::abs(carousel_position_.at(i) - carousel_target_.at(i)) > 0.01f) {
|
||||
// Determinar dirección
|
||||
float direction = (carousel_target_.at(i) > carousel_position_.at(i)) ? 1.0f : -1.0f;
|
||||
|
||||
// Calcular movimiento
|
||||
float movement = CAROUSEL_SPEED * deltaTime * direction;
|
||||
|
||||
// Mover, pero no sobrepasar el target
|
||||
float new_position = carousel_position_.at(i) + movement;
|
||||
|
||||
// Clamp para no sobrepasar
|
||||
if (direction > 0) {
|
||||
carousel_position_.at(i) = std::min(new_position, carousel_target_.at(i));
|
||||
} else {
|
||||
carousel_position_.at(i) = std::max(new_position, carousel_target_.at(i));
|
||||
}
|
||||
} else {
|
||||
// Forzar al target exacto cuando estamos muy cerca
|
||||
carousel_position_.at(i) = carousel_target_.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la lógica del marcador
|
||||
void Scoreboard::update() {
|
||||
void Scoreboard::update(float deltaTime) {
|
||||
fillBackgroundTexture();
|
||||
updateTimeCounter();
|
||||
updateNameColorIndex();
|
||||
updateCarouselAnimation(deltaTime);
|
||||
}
|
||||
|
||||
// Pinta el marcador
|
||||
@@ -432,55 +496,75 @@ void Scoreboard::renderSeparator() {
|
||||
SDL_RenderLine(renderer_, 0, 0, rect_.w, 0);
|
||||
}
|
||||
|
||||
// Pinta el carrusel de caracteres con efecto de color LERP
|
||||
// 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) {
|
||||
const std::string& carousel = carousel_.at(panel_index);
|
||||
if (carousel.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Espacio extra entre letras (además del ancho natural de cada letra)
|
||||
// Espacio extra entre letras
|
||||
constexpr int EXTRA_SPACING = 2;
|
||||
|
||||
// Índice de la letra central
|
||||
const int CENTER_INDEX = carousel.size() / 2;
|
||||
// Carrusel extendido: 9 letras visibles (4 izq + centro + 4 der)
|
||||
constexpr int VISIBLE_LETTERS = 9;
|
||||
constexpr int HALF_VISIBLE = VISIBLE_LETTERS / 2; // 4
|
||||
|
||||
// Calcular el ancho acumulado antes de la letra central
|
||||
int width_before_center = 0;
|
||||
for (int i = 0; i < CENTER_INDEX; ++i) {
|
||||
std::string ch(1, carousel[i]);
|
||||
width_before_center += text_->length(ch, 1) + EXTRA_SPACING;
|
||||
// Posición flotante actual del carrusel
|
||||
const float carousel_pos = carousel_position_.at(panel_index);
|
||||
|
||||
// Calcular ancho promedio de una letra (asumimos ancho uniforme para simplificar)
|
||||
std::string sample_char(1, carousel[carousel.size() / 2]);
|
||||
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<int>(fractional_offset * CHAR_STEP);
|
||||
|
||||
// Índice base (centro del carrusel)
|
||||
const int base_index = static_cast<int>(std::floor(carousel_pos));
|
||||
|
||||
// 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;
|
||||
|
||||
// Renderizar las 9 letras visibles
|
||||
for (int i = -HALF_VISIBLE; i <= HALF_VISIBLE; ++i) {
|
||||
// Índice real en la lista de caracteres (con wrap-around circular)
|
||||
int char_index = base_index + i;
|
||||
const int carousel_size = static_cast<int>(carousel.size());
|
||||
|
||||
// Wrap-around circular
|
||||
while (char_index < 0) {
|
||||
char_index += carousel_size;
|
||||
}
|
||||
while (char_index >= carousel_size) {
|
||||
char_index -= carousel_size;
|
||||
}
|
||||
|
||||
// Calcular posición inicial para que la letra central esté centrada en center_x
|
||||
std::string center_char(1, carousel[CENTER_INDEX]);
|
||||
const int CENTER_CHAR_WIDTH = text_->length(center_char, 1);
|
||||
const int CAROUSEL_START_X = center_x - width_before_center - (CENTER_CHAR_WIDTH / 2);
|
||||
// Obtener el carácter
|
||||
std::string single_char(1, carousel[char_index]);
|
||||
|
||||
// Pintar cada letra individualmente
|
||||
int current_x = CAROUSEL_START_X;
|
||||
for (size_t i = 0; i < carousel.size(); ++i) {
|
||||
std::string single_char(1, carousel[i]);
|
||||
// Calcular distancia flotante al centro visual
|
||||
const float distance_from_center = std::abs(static_cast<float>(i) + fractional_offset);
|
||||
|
||||
// Calcular color con LERP dinámico
|
||||
Color letter_color;
|
||||
|
||||
if (static_cast<int>(i) == CENTER_INDEX) {
|
||||
// Letra central: usa animated_color_ sin modificar
|
||||
if (distance_from_center < 0.5f) {
|
||||
// Letra central: animated_color_
|
||||
letter_color = animated_color_;
|
||||
} else {
|
||||
// Letras laterales: LERP desde text_color1_ hacia color_, pero sin llegar al 100%
|
||||
const int DISTANCE = std::abs(static_cast<int>(i) - CENTER_INDEX);
|
||||
const float MAX_DISTANCE = static_cast<float>(CENTER_INDEX);
|
||||
// Limitar el fade al 70% para que las letras sigan siendo visibles
|
||||
const float LERP_FACTOR = (MAX_DISTANCE > 0) ? ((DISTANCE / MAX_DISTANCE) * 0.7f) : 0.0f;
|
||||
|
||||
// Letras laterales: LERP desde text_color1_ hacia color_
|
||||
// Factor: 0.0 cerca del centro, 0.85 en los extremos (85% fade)
|
||||
const float LERP_FACTOR = std::min((distance_from_center - 0.5f) / (HALF_VISIBLE - 0.5f), 1.0f) * 0.85f;
|
||||
letter_color = text_color1_.LERP(color_, LERP_FACTOR);
|
||||
}
|
||||
|
||||
// Pintar la letra
|
||||
text_->writeDX(Text::COLOR, current_x, y, single_char, 1, letter_color);
|
||||
// Calcular posición X de esta letra
|
||||
const int letter_x = start_x + (i + HALF_VISIBLE) * CHAR_STEP;
|
||||
|
||||
// Avanzar posición X: ancho del caracter + espacio extra
|
||||
current_x += text_->length(single_char, 1) + EXTRA_SPACING;
|
||||
// Pintar la letra
|
||||
text_->writeDX(Text::COLOR, letter_x, y, single_char, 1, letter_color);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class Scoreboard {
|
||||
static auto get() -> Scoreboard*; // Obtiene el puntero al objeto Scoreboard
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la lógica del marcador
|
||||
void update(float deltaTime); // Actualiza la lógica del marcador
|
||||
void render(); // Pinta el marcador
|
||||
|
||||
// --- Setters ---
|
||||
@@ -65,7 +65,7 @@ class Scoreboard {
|
||||
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 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) { carousel_.at(static_cast<size_t>(id)) = carousel; }
|
||||
void setCarousel(Id id, const std::string& carousel); // Implementación en .cpp para detectar cambios
|
||||
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 setStage(int stage) { stage_ = stage; }
|
||||
@@ -84,6 +84,9 @@ class Scoreboard {
|
||||
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)> carousel_ = {}; // Caracter seleccionado
|
||||
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_target_ = {}; // Posición objetivo del carrusel
|
||||
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
|
||||
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)
|
||||
@@ -118,6 +121,7 @@ class Scoreboard {
|
||||
void fillBackgroundTexture(); // Rellena la textura de fondo
|
||||
void updateTimeCounter(); // Actualiza el contador
|
||||
void updateNameColorIndex(); // Actualiza el índice del color animado del nombre
|
||||
void updateCarouselAnimation(float deltaTime); // Actualiza la animación del carrusel
|
||||
void renderSeparator(); // Dibuja la línea que separa la zona de juego del marcador
|
||||
void renderPanelContent(size_t panel_index);
|
||||
void renderScoreMode(size_t panel_index);
|
||||
|
||||
@@ -344,7 +344,7 @@ void Game::updateStage() {
|
||||
void Game::updateGameStateGameOver(float deltaTime) {
|
||||
fade_out_->update();
|
||||
updatePlayers(deltaTime);
|
||||
updateScoreboard();
|
||||
updateScoreboard(deltaTime);
|
||||
updateBackground(deltaTime);
|
||||
balloon_manager_->update(deltaTime);
|
||||
tabe_->update(deltaTime);
|
||||
@@ -380,7 +380,7 @@ void Game::updateGameStateGameOver(float deltaTime) {
|
||||
// Gestiona eventos para el estado del final del juego
|
||||
void Game::updateGameStateCompleted(float deltaTime) {
|
||||
updatePlayers(deltaTime);
|
||||
updateScoreboard();
|
||||
updateScoreboard(deltaTime);
|
||||
updateBackground(deltaTime);
|
||||
balloon_manager_->update(deltaTime);
|
||||
tabe_->update(deltaTime);
|
||||
@@ -1145,7 +1145,7 @@ void Game::handleEvents() {
|
||||
}
|
||||
|
||||
// Actualiza el marcador
|
||||
void Game::updateScoreboard() {
|
||||
void Game::updateScoreboard(float deltaTime) {
|
||||
for (const auto& player : players_) {
|
||||
scoreboard_->setScore(player->getScoreBoardPanel(), player->getScore());
|
||||
scoreboard_->setMult(player->getScoreBoardPanel(), player->getScoreMultiplier());
|
||||
@@ -1157,7 +1157,7 @@ void Game::updateScoreboard() {
|
||||
scoreboard_->setHiScore(hi_score_.score);
|
||||
scoreboard_->setHiScoreName(hi_score_.name);
|
||||
|
||||
scoreboard_->update();
|
||||
scoreboard_->update(deltaTime);
|
||||
}
|
||||
|
||||
// Pone en el marcador el nombre del primer jugador de la tabla
|
||||
@@ -1743,7 +1743,7 @@ void Game::updateRecording(float deltaTime) {
|
||||
// Actualiza las variables durante dicho estado
|
||||
void Game::updateGameStateFadeIn(float deltaTime) {
|
||||
fade_in_->update();
|
||||
updateScoreboard();
|
||||
updateScoreboard(deltaTime);
|
||||
updateBackground(deltaTime);
|
||||
if (fade_in_->hasEnded()) {
|
||||
setState(State::ENTERING_PLAYER);
|
||||
@@ -1756,7 +1756,7 @@ void Game::updateGameStateFadeIn(float deltaTime) {
|
||||
void Game::updateGameStateEnteringPlayer(float deltaTime) {
|
||||
balloon_manager_->update(deltaTime);
|
||||
updatePlayers(deltaTime);
|
||||
updateScoreboard();
|
||||
updateScoreboard(deltaTime);
|
||||
updateBackground(deltaTime);
|
||||
for (const auto& player : players_) {
|
||||
if (player->isPlaying()) {
|
||||
@@ -1790,7 +1790,7 @@ void Game::updateGameStatePlaying(float deltaTime) {
|
||||
#endif
|
||||
updatePlayers(deltaTime);
|
||||
checkPlayersStatusPlaying();
|
||||
updateScoreboard();
|
||||
updateScoreboard(deltaTime);
|
||||
updateBackground(deltaTime);
|
||||
balloon_manager_->update(deltaTime);
|
||||
tabe_->update(deltaTime);
|
||||
|
||||
@@ -317,7 +317,7 @@ class Game {
|
||||
|
||||
// --- Puntuación y marcador ---
|
||||
void updateHiScore(); // Actualiza el récord máximo si es necesario
|
||||
void updateScoreboard(); // Actualiza la visualización del marcador
|
||||
void updateScoreboard(float deltaTime); // Actualiza la visualización del marcador
|
||||
void updateHiScoreName(); // Pone en el marcador el nombre del primer jugador de la tabla
|
||||
void initScoreboard(); // Inicializa el sistema de puntuación
|
||||
|
||||
|
||||
Reference in New Issue
Block a user