feat(anim): cardinal WEST i flip totalment governat pel motor d'animació

This commit is contained in:
JailDesigner committed 2026-04-29 10:11:27 +02:00
1 parent 9dc7ff0da3
commit 72384c3113
15 files changed
+183 -182

No files matched your search

@@ -93,14 +93,13 @@ void AnimatedSprite::animate(float delta_time) {
const float TOTAL = std::accumulate(anim.speeds.begin(), anim.speeds.end(), 0.0F);
// Helper local per a propagar el frame actual (clip + opcionalment flip)
// al sprite. El flip només s'escriu si l'animació declara `controls_flip`,
// per a no trepitjar el flip que el codi del joc encara controla
// externament en animacions sense declaració de flip al YAML.
// Helper local per a propagar el frame actual (clip + flip) al sprite.
// El motor sempre sobreescriu el flip — si el YAML no declara `flip_h`/
// `flip_v`, el frame té els flags a false i el resultat és `SDL_FLIP_NONE`.
auto apply_current_frame = [&](int frame_index) {
const auto& frame = anim.frames[frame_index];
setClip(frame.rect);
if (anim.controls_flip) { setFlip(toFlipMode(frame.flip_h, frame.flip_v)); }
setFlip(toFlipMode(frame.flip_h, frame.flip_v));
};
if (anim.accumulated_time >= TOTAL) {
@@ -151,7 +150,7 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name) {
anim.completed = false;
if (!anim.frames.empty()) {
setClip(anim.frames[0].rect);
if (anim.controls_flip) { setFlip(toFlipMode(anim.frames[0].flip_h, anim.frames[0].flip_v)); }
setFlip(toFlipMode(anim.frames[0].flip_h, anim.frames[0].flip_v));
}
}
@@ -34,6 +34,13 @@ class AnimatedSprite : public MovingSprite {
// 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ó.
//
// El flip és sempre propietat del motor: a cada `animate()` s'escriu el
// flip del frame actual al sprite (default `SDL_FLIP_NONE` quan el YAML
// no declara res). El codi del joc no pot — ni ha de — tocar el flip
// manualment; ho expressa al YAML declarant `flip_h: true` a l'animació
// simètrica (p. ex. `walk_west`) o, per a casos puntuals, per frame
// amb la forma mapping `{ index, flip_h?, flip_v? }`.
struct AnimationData {
std::vector<Frame> frames;
// Durada de cada frame en segons (convertit des de `frame_ms` al YAML).
@@ -44,13 +51,6 @@ class AnimatedSprite : public MovingSprite {
// 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};
@@ -1,6 +1,3 @@
#include <algorithm>
#include <ranges>
#include "core/rendering/sprite/animated_sprite.hpp"
// Implementació del parser pure de YAML d'animacions. Viu en una unitat
@@ -53,16 +50,6 @@ namespace {
return frames;
}
// Detecta si dins de `frames_node` hi ha algun element en forma mapping.
// Si n'hi ha (encara que els flags interns siguin false), l'animació
// passa a controlar el flip — el mapping és senyal explícit que l'autor
// del YAML vol governar el flip per frame.
auto framesContainMapping(const fkyaml::node& frames_node) -> bool {
return std::ranges::any_of(frames_node, [](const auto& frame_node) {
return frame_node.is_mapping();
});
}
// `frame_ms` pot ser un escalar (temps uniforme) o una llista (per-frame).
// Convertim sempre a segons perquè `animate()` treballa amb delta_time
// en segons. Si falta o val 0, `speeds` queda buit i l'animació es
@@ -116,14 +103,7 @@ auto AnimatedSprite::parseAnimationsFromYaml(const fkyaml::node& yaml, const She
AnimationData animation;
if (anim_node.contains("frames") && anim_node["frames"].is_sequence()) {
const auto& frames_node = anim_node["frames"];
animation.frames = convertYamlFrames(frames_node, params, anim_flip_h, anim_flip_v);
// L'animació passa a "controlar" el flip si l'autor ha
// declarat qualsevol cosa relacionada amb flip — sigui a
// nivell d'anim o a través d'un frame en forma mapping.
// Sense cap declaració, ens mantenim passius i deixem el
// flip al codi del joc (backward-compat amb sam.yaml).
animation.controls_flip = anim_flip_h || anim_flip_v || framesContainMapping(frames_node);
animation.frames = convertYamlFrames(anim_node["frames"], params, anim_flip_h, anim_flip_v);
}
parseFrameTimes(anim_node, animation);
parseLoopPolicy(anim_node, animation);