#include "scenes/timeline.hpp" #include namespace scenes { Timeline& Timeline::step(int duration_ms, StepFn fn) { Step s; s.duration_ms = duration_ms; s.continuous = std::move(fn); steps_.push_back(std::move(s)); return *this; } Timeline& Timeline::once(OnceFn fn) { Step s; s.duration_ms = 0; s.oneshot = std::move(fn); steps_.push_back(std::move(s)); return *this; } void Timeline::flushOneShots() { while (current_ < steps_.size() && steps_[current_].duration_ms == 0) { auto& s = steps_[current_]; if (!s.entered) { s.entered = true; if (s.oneshot) s.oneshot(); } ++current_; elapsed_in_step_ = 0; } } void Timeline::tick(int delta_ms) { if (skipped_) return; flushOneShots(); if (current_ >= steps_.size()) return; auto& s = steps_[current_]; if (!s.entered) { s.entered = true; // Primer tick dins del pas: cridem amb progress=0 si hi ha callback. if (s.continuous) s.continuous(0.0f); } elapsed_in_step_ += delta_ms; if (elapsed_in_step_ >= s.duration_ms) { // Tancament del pas: una crida final amb progress=1. if (s.continuous) s.continuous(1.0f); ++current_; elapsed_in_step_ = 0; // Pot ser que el següent pas siga una cadena de one-shots. flushOneShots(); } else if (s.continuous) { const float p = static_cast(elapsed_in_step_) / static_cast(std::max(1, s.duration_ms)); s.continuous(p); } } void Timeline::skip() { skipped_ = true; current_ = steps_.size(); } void Timeline::reset() { for (auto& s : steps_) s.entered = false; current_ = 0; elapsed_in_step_ = 0; skipped_ = false; } bool Timeline::done() const { return skipped_ || current_ >= steps_.size(); } float Timeline::currentProgress() const { if (current_ >= steps_.size()) return 1.0f; const auto& s = steps_[current_]; if (s.duration_ms <= 0) return 0.0f; return static_cast(elapsed_in_step_) / static_cast(s.duration_ms); } } // namespace scenes