#pragma once #include #include #include #include #include "core/rendering/sprite/moving_sprite.hpp" #include "core/resources/resource_types.hpp" #include "external/fkyaml_node.hpp" class AnimatedSprite : public MovingSprite { public: // Un frame d'animació = rectangle dins el spritesheet + flags de flip // associats. El flip s'aplica al sprite a `animate()` quan l'animació // declara que ella controla el flip (vegeu `AnimationData::controls_flip`). struct Frame { SDL_FRect rect{.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; bool flip_h{false}; bool flip_v{false}; }; // Paràmetres geomètrics del spritesheet, derivats del bloc `sprite:` // del YAML. Es passen al parser d'animacions per a calcular els // rectangles de cada frame a partir dels seus índexs. struct SheetParams { float frame_width{0.0F}; float frame_height{0.0F}; int frames_per_row{1}; int max_tiles{1}; }; // Dades d'una animació concreta dins d'un spritesheet. Les claus del // mapa (`animations_`) són els noms; aquí només es guarden els fotogrames // i l'estat de reproducció. struct AnimationData { std::vector frames; // Durada de cada frame en segons (convertit des de `frame_ms` al YAML). // Si té un sol valor, val per a tots els frames; altrament ha de tenir // la mateixa mida que `frames`. std::vector speeds; // -1 = no loop (es queda al darrer frame i marca `completed`). // 0 = loop complet des del primer frame. // N>0 = rebota al frame N en passar del final. int loop_from{0}; // Si true, `animate()` escriu el flip del frame actual al sprite. // Si false (cas backward-compat per a animacions sense cap declaració // de flip), `animate()` no toca el flip — el codi del joc el segueix // controlant externament via `setFlip(...)`. Es marca a true quan // l'animació declara `flip_h`/`flip_v`, o quan algun frame es declara // amb la forma mapping `{ index, flip_h?, flip_v? }`. bool controls_flip{false}; bool completed{false}; int current_frame{0}; float accumulated_time{0.0F}; }; explicit AnimatedSprite(const AnimationResource& cached_data); ~AnimatedSprite() override = default; void update(float delta_time) override; auto animationIsCompleted() -> bool; void setCurrentAnimation(const std::string& name); void resetAnimation(); void animate(float delta_time); // Helper de parsing exposat per a testabilitat. NO toca el cache de // recursos — només el bloc `animations:` del YAML i els paràmetres de // full ja calculats. El ctor d'`AnimatedSprite` el crida internament. static auto parseAnimationsFromYaml(const fkyaml::node& yaml, const SheetParams& params) -> std::unordered_map; private: std::unordered_map animations_; // Nom de l'animació activa. Buit fins que algú crida `setCurrentAnimation`. std::string current_animation_; };