#pragma once #include "Easing.h" // namespace TweenNameSpace { typedef float(*eFunc)(float); // }; // using namespace TweenNameSpace; typedef float(*eFunc)(float); class Tween { /////// private: static inline Tween* head = nullptr; static inline Tween* last = nullptr; static inline uint32_t frameRateTimer; Tween* next; public: static void tick() { Tween* current = Tween::head; while (current != nullptr) { current->update(); current = current->next; } } Tween(uint16_t fps) { frameTime = 1000 / fps; if (Tween::head == nullptr) { Tween::head = this; } if (last != nullptr) { last->next = this; } last = this; } /////// private: uint16_t frameTime; float dt; uint32_t oldMillis; static float lerp(float a, float b, float t) { return a + (b - a) * t; } float from; float to; float duration; eFunc easing = nullptr; float progress; bool isPlayingF; void dtTick() { uint32_t loopStartTime = millis(); dt = (loopStartTime - oldMillis) / 1000.0; oldMillis = loopStartTime; } public: void update() { if (!isPlayingF || easing == nullptr) return; if (millis() - frameRateTimer > frameTime) { frameRateTimer = millis(); dtTick(); if (current == to || progress >= duration) { stop(); return; } current = clamp(Tween::lerp(from, to, easing(progress / duration)), from, to); progress = progress + Tween::dt; } } float current; void start(float from, float to, uint16_t duration, eFunc easing) { if (from == to) { return; } this->from = from; this->to = to; this->duration = duration / 1000.0; this->easing = easing; resetToStart(); dtTick(); isPlayingF = true; } void resetToStart() { progress = 0; } void stop() { isPlayingF = false; } bool isPlaying() { return isPlayingF; } private: int clamp(int value, int a, int b) { if (a > b) { a ^= b; b ^= a; a ^= b; } if (value < a) return a; else if (value > b) return b; else return value; } };