motor de animacio
This commit is contained in:
2026-04-08 08:45:35 +02:00
parent 2019e8f310
commit 947bcceaf9
117 changed files with 86 additions and 694 deletions

View File

@@ -1,5 +1,6 @@
#include "core/rendering/sprite/animated_sprite.hpp"
#include <cmath> // Para std::fmod
#include <cstddef> // Para size_t
#include <fstream> // Para basic_ostream, basic_istream, operator<<, basic...
#include <iostream> // Para cout, cerr
@@ -88,17 +89,7 @@ auto AnimatedSprite::loadAnimationsFromYAML(const std::string& file_path, std::s
animation.name = anim_node["name"].get_value<std::string>();
}
// Parse speed (seconds per frame)
if (anim_node.contains("speed")) {
animation.speed = anim_node["speed"].get_value<float>();
}
// Parse loop frame index
if (anim_node.contains("loop")) {
animation.loop = anim_node["loop"].get_value<int>();
}
// Parse frames array
// Parse frames array (antes de speeds, para saber cuántos frames hay)
if (anim_node.contains("frames") && anim_node["frames"].is_sequence()) {
animation.frames = convertYAMLFramesToRects(
anim_node["frames"],
@@ -108,6 +99,26 @@ auto AnimatedSprite::loadAnimationsFromYAML(const std::string& file_path, std::s
max_tiles);
}
// Parse speed: escalar (uniforme) o array (por frame)
if (anim_node.contains("speed")) {
const auto& speed_node = anim_node["speed"];
if (speed_node.is_sequence()) {
for (const auto& s : speed_node) {
animation.speeds.push_back(s.get_value<float>());
}
} else {
float spd = speed_node.get_value<float>();
if (spd > 0.0F) {
animation.speeds.assign(animation.frames.size(), spd);
}
}
}
// Parse loopFrom
if (anim_node.contains("loopFrom")) {
animation.loop_from = anim_node["loopFrom"].get_value<int>();
}
animations.push_back(animation);
}
}
@@ -172,17 +183,7 @@ AnimatedSprite::AnimatedSprite(const AnimationResource& cached_data) {
animation.name = anim_node["name"].get_value<std::string>();
}
// Parse speed (seconds per frame)
if (anim_node.contains("speed")) {
animation.speed = anim_node["speed"].get_value<float>();
}
// Parse loop frame index
if (anim_node.contains("loop")) {
animation.loop = anim_node["loop"].get_value<int>();
}
// Parse frames array
// Parse frames array (antes de speeds, para saber cuántos frames hay)
if (anim_node.contains("frames") && anim_node["frames"].is_sequence()) {
animation.frames = convertYAMLFramesToRects(
anim_node["frames"],
@@ -192,6 +193,26 @@ AnimatedSprite::AnimatedSprite(const AnimationResource& cached_data) {
max_tiles);
}
// Parse speed: escalar (uniforme) o array (por frame)
if (anim_node.contains("speed")) {
const auto& speed_node = anim_node["speed"];
if (speed_node.is_sequence()) {
for (const auto& s : speed_node) {
animation.speeds.push_back(s.get_value<float>());
}
} else {
float spd = speed_node.get_value<float>();
if (spd > 0.0F) {
animation.speeds.assign(animation.frames.size(), spd);
}
}
}
// Parse loopFrom
if (anim_node.contains("loopFrom")) {
animation.loop_from = anim_node["loopFrom"].get_value<int>();
}
animations_.push_back(animation);
}
}
@@ -240,51 +261,45 @@ auto AnimatedSprite::getIndex(const std::string& name) -> int { // NOLINT(reada
// Calcula el frame correspondiente a la animación (time-based)
void AnimatedSprite::animate(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
if (animations_.empty()) { return; }
if (animations_[current_animation_].speed <= 0.0F) {
return;
auto& anim = animations_[current_animation_];
if (anim.speeds.empty()) { return; } // Animación estática
anim.accumulated_time += delta_time;
// Calcular duración total de la animación
float total = 0.0F;
for (auto s : anim.speeds) { total += s; }
// Si hemos superado la duración total, manejar loop o congelar
if (anim.accumulated_time >= total) {
if (anim.loop_from < 0) {
// Sin loop: congelar en el último frame
anim.current_frame = static_cast<int>(anim.frames.size()) - 1;
anim.completed = true;
setClip(anim.frames[anim.current_frame]);
return;
}
// Con loop: envolver el tiempo en el rango del loop
float loop_start = 0.0F;
for (int i = 0; i < anim.loop_from; ++i) { loop_start += anim.speeds[i]; }
float loop_len = total - loop_start;
anim.accumulated_time = loop_start + std::fmod(anim.accumulated_time - loop_start, loop_len);
}
// Acumula el tiempo transcurrido
animations_[current_animation_].accumulated_time += delta_time;
// Calcula el frame actual a partir del tiempo acumulado
const int TARGET_FRAME = static_cast<int>(
animations_[current_animation_].accumulated_time /
animations_[current_animation_].speed);
// Si alcanza el final de la animación, maneja el loop
if (TARGET_FRAME >= static_cast<int>(animations_[current_animation_].frames.size())) {
if (animations_[current_animation_].loop == -1) {
// Si no hay loop, congela en el último frame
animations_[current_animation_].current_frame =
static_cast<int>(animations_[current_animation_].frames.size()) - 1;
animations_[current_animation_].completed = true;
// Establece el clip del último frame
if (animations_[current_animation_].current_frame >= 0) {
setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
}
} else {
// Si hay loop, vuelve al frame indicado
animations_[current_animation_].accumulated_time =
static_cast<float>(animations_[current_animation_].loop) *
animations_[current_animation_].speed;
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
// Establece el clip del frame de loop
setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
}
} else {
// Actualiza el frame actual
animations_[current_animation_].current_frame = TARGET_FRAME;
// Establece el clip del frame actual
if (animations_[current_animation_].current_frame >= 0 &&
animations_[current_animation_].current_frame <
static_cast<int>(animations_[current_animation_].frames.size())) {
setClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
// Buscar el frame correspondiente al tiempo acumulado
float cursor = 0.0F;
for (int i = 0; i < static_cast<int>(anim.frames.size()); ++i) {
cursor += anim.speeds[i];
if (anim.accumulated_time < cursor) {
anim.current_frame = i;
setClip(anim.frames[i]);
return;
}
}
// Seguridad: último frame
anim.current_frame = static_cast<int>(anim.frames.size()) - 1;
setClip(anim.frames[anim.current_frame]);
}
// Comprueba si ha terminado la animación

View File

@@ -20,8 +20,8 @@ class AnimatedSprite : public MovingSprite {
struct AnimationData {
std::string name; // Nombre de la animacion
std::vector<SDL_FRect> frames; // Cada uno de los frames que componen la animación
float speed{0.083F}; // Velocidad de la animación (segundos por frame)
int loop{0}; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
std::vector<float> speeds; // Duración de cada frame en segundos (vacío = animación estática)
int loop_from{-1}; // Frame al que volver al acabar (-1 = sin loop, congela en el último)
bool completed{false}; // Indica si ha finalizado la animación
int current_frame{0}; // Frame actual
float accumulated_time{0.0F}; // Tiempo acumulado para las animaciones (time-based)