#pragma once #include #include #include // Component reutilitzable d'animació: qualsevol entitat que necessiti // reproduir una seqüència de frames l'instancia. Es manté com a camp // opcional dins d'Entity (veure `entity.hpp`) i NO hereta de cap classe // del pipeline de sprites existent: això manté les entitats estàtiques // (hazards invisibles, triggers) lliures de l'estat d'animació. // // Els frames s'expressen com a índexs enters dins d'un spritesheet. Quan // algun dia aterri l'art definitiu, el renderer consultarà `currentFrame()` // i traduirà l'índex al rectangle del sprite corresponent. De moment els // placeholders tenen un únic frame i `currentFrame()` retorna sempre 0. // // El flip (H/V) és propietat de l'animació, no del codi del joc: el YAML // declara `flip_h`/`flip_v` al bloc d'animació i el component els exposa // via `flipMode()`. Les entitats apliquen aquest valor al seu `flip_` quan // canvien d'animació, sense decidir-lo per direcció. Així una mòmia que va // cap a l'oest reprodueix `walk_west` (frames de l'est + `flip_h: true`) // sense que el codi de la mòmia toqui flip directament. class AnimationComponent { public: AnimationComponent() = default; AnimationComponent(std::vector frames, float fps, bool loop); AnimationComponent(std::vector frames, float fps, bool loop, bool flip_h, bool flip_v); // Avanç del temps. Si `frames_` està buit o té un sol element, no fa // res. En mode loop, `current_frame_` rebota a 0 en passar del final; // en mode no-loop, es queda al darrer frame i `completed()` passa a // true. void tick(float delta_time); // Torna al primer frame i reinicia l'acumulador. Útil en transicions // d'estat (p.ex. Sarcòfag: CLOSED → OPENING reinicia l'animació). void reset(); // Índex actual dins `frames_`. Si `frames_` està buit retorna 0 com // a fallback tolerant (el loader ja ha emès warning si hi havia // frames fora de rang; aquí preferim no crashejar). [[nodiscard]] auto currentFrame() const -> int; [[nodiscard]] auto frameCount() const -> std::size_t { return frames_.size(); } [[nodiscard]] auto completed() const -> bool { return completed_; } [[nodiscard]] auto loops() const -> bool { return loop_; } [[nodiscard]] auto flipH() const -> bool { return flip_h_; } [[nodiscard]] auto flipV() const -> bool { return flip_v_; } // Combinació dels dos flags al `SDL_FlipMode` que entén el render. // SDL3 no admet bitmask: si fos VH simultani, prioritzem H (cap cas // pràctic actual el necessita combinat). [[nodiscard]] auto flipMode() const -> SDL_FlipMode; private: std::vector frames_; float fps_{1.0F}; bool loop_{true}; bool flip_h_{false}; bool flip_v_{false}; int current_{0}; float accumulator_{0.0F}; bool completed_{false}; };