diff --git a/source/path_sprite.cpp b/source/path_sprite.cpp index 4a44e21..6066871 100644 --- a/source/path_sprite.cpp +++ b/source/path_sprite.cpp @@ -4,6 +4,13 @@ #include // Para function #include // Para move +// Constructor para paths por puntos (compatibilidad) +Path::Path(const std::vector &spots_init, int waiting_counter_init) + : spots(spots_init), is_point_path(true) { + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; + waiting_time_ms = static_cast(waiting_counter_init) * FRAME_TIME_MS; +} + // Devuelve un vector con los puntos que conforman la ruta auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function &easing_function) -> std::vector { std::vector v; @@ -32,10 +39,16 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step return v; } -// Actualiza la posición y comprueba si ha llegado a su destino +// Actualiza la posición y comprueba si ha llegado a su destino (compatibilidad) void PathSprite::update() { + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS + update(FRAME_TIME_MS); +} + +// Actualiza la posición y comprueba si ha llegado a su destino +void PathSprite::update(float delta_time) { if (enabled_ && !has_finished_) { - moveThroughCurrentPath(); + moveThroughCurrentPath(delta_time); goToNextPathOrDie(); } } @@ -79,7 +92,13 @@ void PathSprite::addPath(Path path, bool centered) { // Añade un recorrido void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function &easing_function, int waiting_counter) { - paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easing_function), waiting_counter); + // Convertir frames a milisegundos + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; + float duration_ms = static_cast(steps) * FRAME_TIME_MS; + float waiting_ms = static_cast(waiting_counter) * FRAME_TIME_MS; + + paths_.emplace_back(static_cast(start), static_cast(end), type, static_cast(fixed_pos), + duration_ms, waiting_ms, easing_function); } // Añade un recorrido @@ -95,35 +114,78 @@ void PathSprite::enable() { enabled_ = true; - // Establece la posición + // Establece la posición inicial auto &path = paths_.at(current_path_); - const auto &p = path.spots.at(path.counter); - setPosition(p); + if (path.is_point_path) { + const auto &p = path.spots.at(path.counter); + setPosition(p); + } else { + // Para paths generados, establecer posición inicial + SDL_FPoint initial_pos; + if (path.type == PathType::HORIZONTAL) { + initial_pos = {path.start_pos, path.fixed_pos}; + } else { + initial_pos = {path.fixed_pos, path.start_pos}; + } + setPosition(initial_pos); + } } // Coloca el sprite en los diferentes puntos del recorrido -void PathSprite::moveThroughCurrentPath() { +void PathSprite::moveThroughCurrentPath(float delta_time) { auto &path = paths_.at(current_path_); - // Establece la posición - const auto &p = path.spots.at(path.counter); - setPosition(p); + if (path.is_point_path) { + // Lógica para paths por puntos (compatibilidad) + const auto &p = path.spots.at(path.counter); + setPosition(p); - // Comprobar si ha terminado el recorrido - if (!path.on_destination) { - ++path.counter; - if (path.counter >= static_cast(path.spots.size())) { - path.on_destination = true; - path.counter = static_cast(path.spots.size()) - 1; + if (!path.on_destination) { + ++path.counter; + if (path.counter >= static_cast(path.spots.size())) { + path.on_destination = true; + path.counter = static_cast(path.spots.size()) - 1; + } } - } - // Comprobar si ha terminado la espera - if (path.on_destination) { - if (path.waiting_counter == 0) { - path.finished = true; + if (path.on_destination) { + path.waiting_elapsed += delta_time; + if (path.waiting_elapsed >= path.waiting_time_ms) { + path.finished = true; + } + } + } else { + // Lógica para paths generados en tiempo real + if (!path.on_destination) { + path.elapsed_time += delta_time; + + // Calcular progreso (0.0 a 1.0) + float progress = path.elapsed_time / path.duration_ms; + if (progress >= 1.0f) { + progress = 1.0f; + path.on_destination = true; + } + + // Aplicar función de easing + double eased_progress = path.easing_function(progress); + + // Calcular posición actual + float current_pos = path.start_pos + (path.end_pos - path.start_pos) * static_cast(eased_progress); + + // Establecer posición según el tipo + SDL_FPoint position; + if (path.type == PathType::HORIZONTAL) { + position = {current_pos, path.fixed_pos}; + } else { + position = {path.fixed_pos, current_pos}; + } + setPosition(position); } else { - --path.waiting_counter; + // Esperar en destino + path.waiting_elapsed += delta_time; + if (path.waiting_elapsed >= path.waiting_time_ms) { + path.finished = true; + } } } } diff --git a/source/path_sprite.h b/source/path_sprite.h index 7e5646b..e75a6eb 100644 --- a/source/path_sprite.h +++ b/source/path_sprite.h @@ -24,17 +24,31 @@ enum class PathCentered { // Centrado del recorrido }; // --- Estructuras --- -struct Path { // Define un recorrido para el sprite - std::vector spots; // Puntos por los que se desplazará el sprite - int waiting_counter; // Tiempo de espera una vez en el destino - bool on_destination = false; // Indica si ha llegado al destino - bool finished = false; // Indica si ha terminado de esperarse - int counter = 0; // Contador interno +struct Path { // Define un recorrido para el sprite + float start_pos; // Posición inicial + float end_pos; // Posición final + PathType type; // Tipo de movimiento (horizontal/vertical) + float fixed_pos; // Posición fija en el eje contrario + float duration_ms; // Duración de la animación en milisegundos + float waiting_time_ms; // Tiempo de espera una vez en el destino + std::function easing_function; // Función de easing + float elapsed_time = 0.0f; // Tiempo transcurrido + float waiting_elapsed = 0.0f; // Tiempo de espera transcurrido + bool on_destination = false; // Indica si ha llegado al destino + bool finished = false; // Indica si ha terminado de esperarse - // Constructor - Path(const std::vector &spots_init, int waiting_counter_init) - : spots(spots_init), - waiting_counter(waiting_counter_init) {} + // Constructor para paths generados + Path(float start, float end, PathType path_type, float fixed, float duration, float waiting, std::function easing) + : start_pos(start), end_pos(end), type(path_type), fixed_pos(fixed), + duration_ms(duration), waiting_time_ms(waiting), easing_function(std::move(easing)) {} + + // Constructor para paths por puntos (mantenemos compatibilidad) + Path(const std::vector &spots_init, int waiting_counter_init); + + // Variables para paths por puntos + std::vector spots; // Solo para paths por puntos + int counter = 0; // Solo para paths por puntos + bool is_point_path = false; // Indica si es un path por puntos }; // --- Funciones --- @@ -49,7 +63,8 @@ class PathSprite : public Sprite { ~PathSprite() override = default; // --- Métodos principales --- - void update(); // Actualiza la posición del sprite según el recorrido + void update(); // Actualiza la posición del sprite según el recorrido (compatibilidad) + void update(float delta_time); // Actualiza la posición del sprite según el recorrido void render() override; // Muestra el sprite por pantalla // --- Gestión de recorridos --- @@ -72,6 +87,6 @@ class PathSprite : public Sprite { std::vector paths_; // Caminos a recorrer por el sprite // --- Métodos internos --- - void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido + void moveThroughCurrentPath(float delta_time); // Coloca el sprite en los diferentes puntos del recorrido void goToNextPathOrDie(); // Cambia de recorrido o finaliza }; \ No newline at end of file diff --git a/source/sections/intro.cpp b/source/sections/intro.cpp index 36c868b..6596366 100644 --- a/source/sections/intro.cpp +++ b/source/sections/intro.cpp @@ -207,24 +207,21 @@ void Intro::switchText(int from_index, int to_index) { } // Actualiza las variables del objeto -void Intro::update() { - if (SDL_GetTicks() - ticks_ > param.game.speed) { - ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks - Screen::get()->update(); // Actualiza el objeto screen +void Intro::update(float delta_time) { + Screen::get()->update(); // Actualiza el objeto screen - tiled_bg_->update(); // Actualiza el fondo + tiled_bg_->update(delta_time); // Actualiza el fondo - switch (state_) { - case State::SCENES: - updateSprites(); - updateTexts(); - updateScenes(); - break; + switch (state_) { + case State::SCENES: + updateSprites(delta_time); + updateTexts(delta_time); + updateScenes(); + break; - case State::POST: - updatePostState(); - break; - } + case State::POST: + updatePostState(); + break; } Audio::update(); @@ -253,12 +250,24 @@ void Intro::render() { SCREEN->render(); // Vuelca el contenido del renderizador en pantalla } +// Calcula el tiempo transcurrido desde el último frame +float Intro::calculateDeltaTime() { + const Uint64 current_time = SDL_GetTicks(); + const float delta_time = static_cast(current_time - last_time_); + last_time_ = current_time; + return delta_time; +} + // Bucle principal void Intro::run() { + last_time_ = SDL_GetTicks(); Audio::get()->playMusic("intro.ogg", 0); + while (Section::name == Section::Name::INTRO) { + const float delta_time = calculateDeltaTime(); + checkInput(); - update(); + update(delta_time); checkEvents(); // Tiene que ir antes del render render(); } @@ -444,20 +453,20 @@ void Intro::initTexts() { } // Actualiza los sprites -void Intro::updateSprites() { +void Intro::updateSprites(float delta_time) { for (auto &sprite : card_sprites_) { - sprite->update(); + sprite->update(delta_time); } for (auto &sprite : shadow_sprites_) { - sprite->update(); + sprite->update(delta_time); } } // Actualiza los textos -void Intro::updateTexts() { +void Intro::updateTexts(float delta_time) { for (auto &text : texts_) { - text->update(); + text->update(delta_time); } } diff --git a/source/sections/intro.h b/source/sections/intro.h index c4fff41..b2a7f8e 100644 --- a/source/sections/intro.h +++ b/source/sections/intro.h @@ -42,7 +42,7 @@ class Intro { std::unique_ptr tiled_bg_; // Fondo en mosaico // --- Variables --- - Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa + Uint64 last_time_ = 0; // Último timestamp para calcular delta-time int scene_ = 0; // Indica qué escena está activa State state_ = State::SCENES; // Estado principal de la intro PostState post_state_ = PostState::STOP_BG; // Estado POST @@ -50,19 +50,20 @@ class Intro { Color bg_color_ = param.intro.bg_color; // Color de fondo // --- Métodos internos --- - void update(); // Actualiza las variables del objeto + void update(float delta_time); // Actualiza las variables del objeto void render(); // Dibuja el objeto en pantalla static void checkInput(); // Comprueba las entradas static void checkEvents(); // Comprueba los eventos void updateScenes(); // Actualiza las escenas de la intro void initSprites(); // Inicializa las imágenes void initTexts(); // Inicializa los textos - void updateSprites(); // Actualiza los sprites - void updateTexts(); // Actualiza los textos + void updateSprites(float delta_time); // Actualiza los sprites + void updateTexts(float delta_time); // Actualiza los textos void renderSprites(); // Dibuja los sprites void renderTexts(); // Dibuja los textos static void renderTextRect(); // Dibuja el rectangulo de fondo del texto; void updatePostState(); // Actualiza el estado POST + float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame // --- Métodos para manejar cada escena individualmente --- void updateScene0(); diff --git a/source/tiled_bg.cpp b/source/tiled_bg.cpp index 0bf79e0..162bd9e 100644 --- a/source/tiled_bg.cpp +++ b/source/tiled_bg.cpp @@ -81,9 +81,15 @@ void TiledBG::render() { SDL_RenderTexture(renderer_, canvas_, &window_, &pos_); } -// Actualiza la lógica de la clase +// Actualiza la lógica de la clase (compatibilidad) void TiledBG::update() { - updateDesp(); + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS + update(FRAME_TIME_MS); +} + +// Actualiza la lógica de la clase +void TiledBG::update(float delta_time) { + updateDesp(delta_time); updateStop(); switch (mode_) { diff --git a/source/tiled_bg.h b/source/tiled_bg.h index a70fc0e..4b21010 100644 --- a/source/tiled_bg.h +++ b/source/tiled_bg.h @@ -24,8 +24,9 @@ class TiledBG { ~TiledBG(); // --- Métodos principales --- - void render(); // Pinta la clase en pantalla - void update(); // Actualiza la lógica de la clase + void render(); // Pinta la clase en pantalla + void update(); // Actualiza la lógica de la clase (compatibilidad) + void update(float delta_time); // Actualiza la lógica de la clase // --- Configuración --- void setSpeed(float speed) { speed_ = speed; } // Establece la velocidad @@ -54,7 +55,8 @@ class TiledBG { bool stopping_ = false; // Indica si se está deteniendo // --- Métodos internos --- - void fillTexture(); // Rellena la textura con el contenido - void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento - void updateStop(); // Detiene el desplazamiento de forma ordenada + void fillTexture(); // Rellena la textura con el contenido + void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento (compatibilidad) + void updateDesp(float delta_time) { desp_ += speed_ * delta_time / (1000.0f / 60.0f); } // Actualiza el desplazamiento + void updateStop(); // Detiene el desplazamiento de forma ordenada }; \ No newline at end of file diff --git a/source/writer.cpp b/source/writer.cpp index 291b421..49be3f4 100644 --- a/source/writer.cpp +++ b/source/writer.cpp @@ -3,15 +3,14 @@ #include "text.h" // Para Text // Actualiza el objeto -void Writer::update() { +void Writer::update(float delta_time) { if (enabled_) { if (!completed_) { // No completado - if (writing_counter_ > 0) { - writing_counter_--; - } else { + writing_timer_ += delta_time; + if (writing_timer_ >= speed_ms_) { index_++; - writing_counter_ = speed_; + writing_timer_ = 0.0f; } if (index_ == length_) { @@ -19,10 +18,8 @@ void Writer::update() { } } else { // Completado - finished_ = enabled_counter_ <= 0; - if (!finished_) { - enabled_counter_--; - } + enabled_timer_ += delta_time; + finished_ = enabled_timer_ >= enabled_timer_target_; } } } @@ -57,8 +54,10 @@ void Writer::setCaption(const std::string &text) { // Establece el valor de la variable void Writer::setSpeed(int value) { - speed_ = value; - writing_counter_ = value; + // Convierte frames a milisegundos (frames * 16.67ms) + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; + speed_ms_ = static_cast(value) * FRAME_TIME_MS; + writing_timer_ = 0.0f; } // Establece el valor de la variable @@ -73,7 +72,10 @@ auto Writer::isEnabled() const -> bool { // Establece el valor de la variable void Writer::setFinishedCounter(int time) { - enabled_counter_ = time; + // Convierte frames a milisegundos (frames * 16.67ms) + constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; + enabled_timer_target_ = static_cast(time) * FRAME_TIME_MS; + enabled_timer_ = 0.0f; } // Centra la cadena de texto a un punto X diff --git a/source/writer.h b/source/writer.h index a7099ce..b0761a1 100644 --- a/source/writer.h +++ b/source/writer.h @@ -15,7 +15,7 @@ class Writer { ~Writer() = default; // --- Métodos principales --- - void update(); // Actualiza el objeto + void update(float delta_time); // Actualiza el objeto void render() const; // Dibuja el objeto en pantalla // --- Setters --- @@ -38,16 +38,17 @@ class Writer { std::shared_ptr text_; // Objeto encargado de escribir el texto // --- Variables de estado --- - std::string caption_; // El texto para escribir - int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto - int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto - int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres - int speed_ = 0; // Velocidad de escritura - int writing_counter_ = 0; // Temporizador de escritura para cada caracter - int index_ = 0; // Posición del texto que se está escribiendo - int length_ = 0; // Longitud de la cadena a escribir - int enabled_counter_ = 0; // Temporizador para deshabilitar el objeto - bool completed_ = false; // Indica si se ha escrito todo el texto - bool enabled_ = false; // Indica si el objeto está habilitado - bool finished_ = false; // Indica si ya ha terminado + std::string caption_; // El texto para escribir + int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto + int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto + int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres + float speed_ms_ = 0.0f; // Velocidad de escritura en milisegundos + float writing_timer_ = 0.0f; // Temporizador de escritura para cada caracter + int index_ = 0; // Posición del texto que se está escribiendo + int length_ = 0; // Longitud de la cadena a escribir + float enabled_timer_ = 0.0f; // Temporizador para deshabilitar el objeto + float enabled_timer_target_ = 0.0f; // Tiempo objetivo para deshabilitar el objeto + bool completed_ = false; // Indica si se ha escrito todo el texto + bool enabled_ = false; // Indica si el objeto está habilitado + bool finished_ = false; // Indica si ya ha terminado }; \ No newline at end of file