#include "game/scenes/timeline.hpp" #include namespace scenes { auto Timeline::step(int duration_ms, StepFn fn) -> Timeline& { Step s; s.duration_ms = duration_ms; s.continuous = std::move(fn); steps_.push_back(std::move(s)); return *this; } auto Timeline::once(OnceFn fn) -> Timeline& { 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; } auto Timeline::done() const -> bool { return skipped_ || current_ >= steps_.size(); } auto Timeline::currentProgress() const -> float { 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