migració a delta time

This commit is contained in:
2025-09-16 10:48:22 +02:00
parent 6c702e7e23
commit 7579594c22
8 changed files with 189 additions and 91 deletions

View File

@@ -4,6 +4,13 @@
#include <functional> // Para function #include <functional> // Para function
#include <utility> // Para move #include <utility> // Para move
// Constructor para paths por puntos (compatibilidad)
Path::Path(const std::vector<SDL_FPoint> &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<float>(waiting_counter_init) * FRAME_TIME_MS;
}
// Devuelve un vector con los puntos que conforman la ruta // 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<double(double)> &easing_function) -> std::vector<SDL_FPoint> { auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint> {
std::vector<SDL_FPoint> v; std::vector<SDL_FPoint> v;
@@ -32,10 +39,16 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
return v; 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() { 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_) { if (enabled_ && !has_finished_) {
moveThroughCurrentPath(); moveThroughCurrentPath(delta_time);
goToNextPathOrDie(); goToNextPathOrDie();
} }
} }
@@ -79,7 +92,13 @@ void PathSprite::addPath(Path path, bool centered) {
// Añade un recorrido // Añade un recorrido
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter) { void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &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<float>(steps) * FRAME_TIME_MS;
float waiting_ms = static_cast<float>(waiting_counter) * FRAME_TIME_MS;
paths_.emplace_back(static_cast<float>(start), static_cast<float>(end), type, static_cast<float>(fixed_pos),
duration_ms, waiting_ms, easing_function);
} }
// Añade un recorrido // Añade un recorrido
@@ -95,35 +114,78 @@ void PathSprite::enable() {
enabled_ = true; enabled_ = true;
// Establece la posición // Establece la posición inicial
auto &path = paths_.at(current_path_); auto &path = paths_.at(current_path_);
const auto &p = path.spots.at(path.counter); if (path.is_point_path) {
setPosition(p); 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 // Coloca el sprite en los diferentes puntos del recorrido
void PathSprite::moveThroughCurrentPath() { void PathSprite::moveThroughCurrentPath(float delta_time) {
auto &path = paths_.at(current_path_); auto &path = paths_.at(current_path_);
// Establece la posición if (path.is_point_path) {
const auto &p = path.spots.at(path.counter); // Lógica para paths por puntos (compatibilidad)
setPosition(p); const auto &p = path.spots.at(path.counter);
setPosition(p);
// Comprobar si ha terminado el recorrido if (!path.on_destination) {
if (!path.on_destination) { ++path.counter;
++path.counter; if (path.counter >= static_cast<int>(path.spots.size())) {
if (path.counter >= static_cast<int>(path.spots.size())) { path.on_destination = true;
path.on_destination = true; path.counter = static_cast<int>(path.spots.size()) - 1;
path.counter = static_cast<int>(path.spots.size()) - 1; }
} }
}
// Comprobar si ha terminado la espera if (path.on_destination) {
if (path.on_destination) { path.waiting_elapsed += delta_time;
if (path.waiting_counter == 0) { if (path.waiting_elapsed >= path.waiting_time_ms) {
path.finished = true; 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<float>(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 { } else {
--path.waiting_counter; // Esperar en destino
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_ms) {
path.finished = true;
}
} }
} }
} }

View File

@@ -24,17 +24,31 @@ enum class PathCentered { // Centrado del recorrido
}; };
// --- Estructuras --- // --- Estructuras ---
struct Path { // Define un recorrido para el sprite struct Path { // Define un recorrido para el sprite
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite float start_pos; // Posición inicial
int waiting_counter; // Tiempo de espera una vez en el destino float end_pos; // Posición final
bool on_destination = false; // Indica si ha llegado al destino PathType type; // Tipo de movimiento (horizontal/vertical)
bool finished = false; // Indica si ha terminado de esperarse float fixed_pos; // Posición fija en el eje contrario
int counter = 0; // Contador interno 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<double(double)> 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 // Constructor para paths generados
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init) Path(float start, float end, PathType path_type, float fixed, float duration, float waiting, std::function<double(double)> easing)
: spots(spots_init), : start_pos(start), end_pos(end), type(path_type), fixed_pos(fixed),
waiting_counter(waiting_counter_init) {} duration_ms(duration), waiting_time_ms(waiting), easing_function(std::move(easing)) {}
// Constructor para paths por puntos (mantenemos compatibilidad)
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init);
// Variables para paths por puntos
std::vector<SDL_FPoint> 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 --- // --- Funciones ---
@@ -49,7 +63,8 @@ class PathSprite : public Sprite {
~PathSprite() override = default; ~PathSprite() override = default;
// --- Métodos principales --- // --- 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 void render() override; // Muestra el sprite por pantalla
// --- Gestión de recorridos --- // --- Gestión de recorridos ---
@@ -72,6 +87,6 @@ class PathSprite : public Sprite {
std::vector<Path> paths_; // Caminos a recorrer por el sprite std::vector<Path> paths_; // Caminos a recorrer por el sprite
// --- Métodos internos --- // --- 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 void goToNextPathOrDie(); // Cambia de recorrido o finaliza
}; };

View File

@@ -207,24 +207,21 @@ void Intro::switchText(int from_index, int to_index) {
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
void Intro::update() { void Intro::update(float delta_time) {
if (SDL_GetTicks() - ticks_ > param.game.speed) { Screen::get()->update(); // Actualiza el objeto screen
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
Screen::get()->update(); // Actualiza el objeto screen
tiled_bg_->update(); // Actualiza el fondo tiled_bg_->update(delta_time); // Actualiza el fondo
switch (state_) { switch (state_) {
case State::SCENES: case State::SCENES:
updateSprites(); updateSprites(delta_time);
updateTexts(); updateTexts(delta_time);
updateScenes(); updateScenes();
break; break;
case State::POST: case State::POST:
updatePostState(); updatePostState();
break; break;
}
} }
Audio::update(); Audio::update();
@@ -253,12 +250,24 @@ void Intro::render() {
SCREEN->render(); // Vuelca el contenido del renderizador en pantalla 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<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle principal // Bucle principal
void Intro::run() { void Intro::run() {
last_time_ = SDL_GetTicks();
Audio::get()->playMusic("intro.ogg", 0); Audio::get()->playMusic("intro.ogg", 0);
while (Section::name == Section::Name::INTRO) { while (Section::name == Section::Name::INTRO) {
const float delta_time = calculateDeltaTime();
checkInput(); checkInput();
update(); update(delta_time);
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
render(); render();
} }
@@ -444,20 +453,20 @@ void Intro::initTexts() {
} }
// Actualiza los sprites // Actualiza los sprites
void Intro::updateSprites() { void Intro::updateSprites(float delta_time) {
for (auto &sprite : card_sprites_) { for (auto &sprite : card_sprites_) {
sprite->update(); sprite->update(delta_time);
} }
for (auto &sprite : shadow_sprites_) { for (auto &sprite : shadow_sprites_) {
sprite->update(); sprite->update(delta_time);
} }
} }
// Actualiza los textos // Actualiza los textos
void Intro::updateTexts() { void Intro::updateTexts(float delta_time) {
for (auto &text : texts_) { for (auto &text : texts_) {
text->update(); text->update(delta_time);
} }
} }

View File

@@ -42,7 +42,7 @@ class Intro {
std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico
// --- Variables --- // --- 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 int scene_ = 0; // Indica qué escena está activa
State state_ = State::SCENES; // Estado principal de la intro State state_ = State::SCENES; // Estado principal de la intro
PostState post_state_ = PostState::STOP_BG; // Estado POST PostState post_state_ = PostState::STOP_BG; // Estado POST
@@ -50,19 +50,20 @@ class Intro {
Color bg_color_ = param.intro.bg_color; // Color de fondo Color bg_color_ = param.intro.bg_color; // Color de fondo
// --- Métodos internos --- // --- 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 void render(); // Dibuja el objeto en pantalla
static void checkInput(); // Comprueba las entradas static void checkInput(); // Comprueba las entradas
static void checkEvents(); // Comprueba los eventos static void checkEvents(); // Comprueba los eventos
void updateScenes(); // Actualiza las escenas de la intro void updateScenes(); // Actualiza las escenas de la intro
void initSprites(); // Inicializa las imágenes void initSprites(); // Inicializa las imágenes
void initTexts(); // Inicializa los textos void initTexts(); // Inicializa los textos
void updateSprites(); // Actualiza los sprites void updateSprites(float delta_time); // Actualiza los sprites
void updateTexts(); // Actualiza los textos void updateTexts(float delta_time); // Actualiza los textos
void renderSprites(); // Dibuja los sprites void renderSprites(); // Dibuja los sprites
void renderTexts(); // Dibuja los textos void renderTexts(); // Dibuja los textos
static void renderTextRect(); // Dibuja el rectangulo de fondo del texto; static void renderTextRect(); // Dibuja el rectangulo de fondo del texto;
void updatePostState(); // Actualiza el estado POST void updatePostState(); // Actualiza el estado POST
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
// --- Métodos para manejar cada escena individualmente --- // --- Métodos para manejar cada escena individualmente ---
void updateScene0(); void updateScene0();

View File

@@ -81,9 +81,15 @@ void TiledBG::render() {
SDL_RenderTexture(renderer_, canvas_, &window_, &pos_); SDL_RenderTexture(renderer_, canvas_, &window_, &pos_);
} }
// Actualiza la lógica de la clase // Actualiza la lógica de la clase (compatibilidad)
void TiledBG::update() { 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(); updateStop();
switch (mode_) { switch (mode_) {

View File

@@ -24,8 +24,9 @@ class TiledBG {
~TiledBG(); ~TiledBG();
// --- Métodos principales --- // --- Métodos principales ---
void render(); // Pinta la clase en pantalla void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase void update(); // Actualiza la lógica de la clase (compatibilidad)
void update(float delta_time); // Actualiza la lógica de la clase
// --- Configuración --- // --- Configuración ---
void setSpeed(float speed) { speed_ = speed; } // Establece la velocidad void setSpeed(float speed) { speed_ = speed; } // Establece la velocidad
@@ -54,7 +55,8 @@ class TiledBG {
bool stopping_ = false; // Indica si se está deteniendo bool stopping_ = false; // Indica si se está deteniendo
// --- Métodos internos --- // --- Métodos internos ---
void fillTexture(); // Rellena la textura con el contenido void fillTexture(); // Rellena la textura con el contenido
void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento (compatibilidad)
void updateStop(); // Detiene el desplazamiento de forma ordenada void updateDesp(float delta_time) { desp_ += speed_ * delta_time / (1000.0f / 60.0f); } // Actualiza el desplazamiento
void updateStop(); // Detiene el desplazamiento de forma ordenada
}; };

View File

@@ -3,15 +3,14 @@
#include "text.h" // Para Text #include "text.h" // Para Text
// Actualiza el objeto // Actualiza el objeto
void Writer::update() { void Writer::update(float delta_time) {
if (enabled_) { if (enabled_) {
if (!completed_) { if (!completed_) {
// No completado // No completado
if (writing_counter_ > 0) { writing_timer_ += delta_time;
writing_counter_--; if (writing_timer_ >= speed_ms_) {
} else {
index_++; index_++;
writing_counter_ = speed_; writing_timer_ = 0.0f;
} }
if (index_ == length_) { if (index_ == length_) {
@@ -19,10 +18,8 @@ void Writer::update() {
} }
} else { } else {
// Completado // Completado
finished_ = enabled_counter_ <= 0; enabled_timer_ += delta_time;
if (!finished_) { finished_ = enabled_timer_ >= enabled_timer_target_;
enabled_counter_--;
}
} }
} }
} }
@@ -57,8 +54,10 @@ void Writer::setCaption(const std::string &text) {
// Establece el valor de la variable // Establece el valor de la variable
void Writer::setSpeed(int value) { void Writer::setSpeed(int value) {
speed_ = value; // Convierte frames a milisegundos (frames * 16.67ms)
writing_counter_ = value; constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
speed_ms_ = static_cast<float>(value) * FRAME_TIME_MS;
writing_timer_ = 0.0f;
} }
// Establece el valor de la variable // Establece el valor de la variable
@@ -73,7 +72,10 @@ auto Writer::isEnabled() const -> bool {
// Establece el valor de la variable // Establece el valor de la variable
void Writer::setFinishedCounter(int time) { 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<float>(time) * FRAME_TIME_MS;
enabled_timer_ = 0.0f;
} }
// Centra la cadena de texto a un punto X // Centra la cadena de texto a un punto X

View File

@@ -15,7 +15,7 @@ class Writer {
~Writer() = default; ~Writer() = default;
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza el objeto void update(float delta_time); // Actualiza el objeto
void render() const; // Dibuja el objeto en pantalla void render() const; // Dibuja el objeto en pantalla
// --- Setters --- // --- Setters ---
@@ -38,16 +38,17 @@ class Writer {
std::shared_ptr<Text> text_; // Objeto encargado de escribir el texto std::shared_ptr<Text> text_; // Objeto encargado de escribir el texto
// --- Variables de estado --- // --- Variables de estado ---
std::string caption_; // El texto para escribir 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_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 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 kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres
int speed_ = 0; // Velocidad de escritura float speed_ms_ = 0.0f; // Velocidad de escritura en milisegundos
int writing_counter_ = 0; // Temporizador de escritura para cada caracter float writing_timer_ = 0.0f; // Temporizador de escritura para cada caracter
int index_ = 0; // Posición del texto que se está escribiendo int index_ = 0; // Posición del texto que se está escribiendo
int length_ = 0; // Longitud de la cadena a escribir int length_ = 0; // Longitud de la cadena a escribir
int enabled_counter_ = 0; // Temporizador para deshabilitar el objeto float enabled_timer_ = 0.0f; // Temporizador para deshabilitar el objeto
bool completed_ = false; // Indica si se ha escrito todo el texto float enabled_timer_target_ = 0.0f; // Tiempo objetivo para deshabilitar el objeto
bool enabled_ = false; // Indica si el objeto está habilitado bool completed_ = false; // Indica si se ha escrito todo el texto
bool finished_ = false; // Indica si ya ha terminado bool enabled_ = false; // Indica si el objeto está habilitado
bool finished_ = false; // Indica si ya ha terminado
}; };