From 19768cb72bbddbd4c424d03e4c17faf97e98adb8 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Tue, 16 Sep 2025 16:51:31 +0200 Subject: [PATCH] delta-time: animated_sprite.cpp --- source/animated_sprite.cpp | 52 ++++++++++++++++++++++++++++++++++++-- source/animated_sprite.h | 11 +++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/source/animated_sprite.cpp b/source/animated_sprite.cpp index 8e9fb06..c4e2005 100644 --- a/source/animated_sprite.cpp +++ b/source/animated_sprite.cpp @@ -43,6 +43,10 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe std::vector buffer; std::string line; while (std::getline(input_stream, line)) { + // Eliminar caracteres de retorno de carro (\r) al final de la línea + if (!line.empty() && line.back() == '\r') { + line.pop_back(); + } if (!line.empty()) { buffer.push_back(line); } @@ -82,7 +86,7 @@ auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int { return -1; } -// Calcula el frame correspondiente a la animación +// Calcula el frame correspondiente a la animación (frame-based) void AnimatedSprite::animate() { if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) { return; @@ -112,6 +116,39 @@ void AnimatedSprite::animate() { } } +// Calcula el frame correspondiente a la animación (time-based) +void AnimatedSprite::animate(float deltaTime) { + if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) { + return; + } + + // Convertir speed (frames) a tiempo: speed frames = speed/60 segundos a 60fps + float frameTime = static_cast(animations_[current_animation_].speed) / 60.0f; + + // Acumular tiempo transcurrido + animations_[current_animation_].time_accumulator += deltaTime; + + // Verificar si es momento de cambiar frame + if (animations_[current_animation_].time_accumulator >= frameTime) { + animations_[current_animation_].time_accumulator -= frameTime; + animations_[current_animation_].current_frame++; + + // Si alcanza el final de la animación + if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) { + if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame + animations_[current_animation_].current_frame = animations_[current_animation_].frames.size() - 1; + animations_[current_animation_].completed = true; + } else { // Si hay loop, vuelve al frame indicado + animations_[current_animation_].time_accumulator = 0.0f; + animations_[current_animation_].current_frame = animations_[current_animation_].loop; + } + } + + // Actualizar el sprite clip + updateSpriteClip(); + } +} + // Comprueba si ha terminado la animación auto AnimatedSprite::animationIsCompleted() -> bool { return animations_[current_animation_].completed; @@ -126,10 +163,12 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) { if (reset) { animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; + animations_[current_animation_].time_accumulator = 0.0f; animations_[current_animation_].completed = false; } else { animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size() - 1); animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; + animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; } updateSpriteClip(); @@ -145,26 +184,35 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) { if (reset) { animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; + animations_[current_animation_].time_accumulator = 0.0f; animations_[current_animation_].completed = false; } else { animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size()); animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; + animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; } updateSpriteClip(); } } -// Actualiza las variables del objeto +// Actualiza las variables del objeto (frame-based) void AnimatedSprite::update() { animate(); MovingSprite::update(); } +// Actualiza las variables del objeto (time-based) +void AnimatedSprite::update(float deltaTime) { + animate(deltaTime); + MovingSprite::update(deltaTime); +} + // Reinicia la animación void AnimatedSprite::resetAnimation() { animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; + animations_[current_animation_].time_accumulator = 0.0f; animations_[current_animation_].completed = false; animations_[current_animation_].paused = false; updateSpriteClip(); diff --git a/source/animated_sprite.h b/source/animated_sprite.h index 3adcd21..b32185f 100644 --- a/source/animated_sprite.h +++ b/source/animated_sprite.h @@ -21,11 +21,12 @@ struct Animation { std::string name; // Nombre de la animación std::vector frames; // Frames que componen la animación - int speed{DEFAULT_SPEED}; // Velocidad de reproducción + int speed{DEFAULT_SPEED}; // Velocidad de reproducción (frame-based) int loop{0}; // Frame de vuelta al terminar (-1 para no repetir) bool completed{false}; // Indica si la animación ha finalizado size_t current_frame{0}; // Frame actual en reproducción - int counter{0}; // Contador para la animación + int counter{0}; // Contador para la animación (frame-based) + float time_accumulator{0.0f}; // Acumulador de tiempo para animaciones time-based bool paused{false}; // La animación no avanza Animation() = default; @@ -55,7 +56,8 @@ class AnimatedSprite : public MovingSprite { ~AnimatedSprite() override = default; // --- Métodos principales --- - void update() override; // Actualiza la animación + void update() override; // Actualiza la animación (frame-based) + void update(float deltaTime); // Actualiza la animación (time-based) // --- Control de animaciones --- void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre @@ -78,7 +80,8 @@ class AnimatedSprite : public MovingSprite { int current_animation_ = 0; // Índice de la animación activa // --- Métodos internos --- - void animate(); // Calcula el frame correspondiente a la animación + void animate(); // Calcula el frame correspondiente a la animación (frame-based) + void animate(float deltaTime); // Calcula el frame correspondiente a la animación (time-based) void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame