Files
Tween/Tween.h
2025-05-12 17:26:13 +03:00

181 lines
4.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include "Easing.h"
#include "TimeWarp.h"
namespace EasingFunc {
// typedef float (*eFunc)(float); // тип easing-функции, как у Вас
// Статические данные для обёртки
static const TimeWarp* g_warp = nullptr;
static eFunc g_baseEasing = nullptr;
// Обёртка с модификатором времени (вызывается Tween'ом)
inline float _easingWithWarp(float t) {
if (!g_warp || !g_baseEasing) return t;
float warpedT = g_warp->apply(t);
return g_baseEasing(warpedT);
}
// Установить текущий модификатор времени
inline eFunc withTimeWarp(eFunc easing, const TimeWarp& warp) {
g_warp = &warp;
g_baseEasing = easing;
return _easingWithWarp;
}
}; // namespace EasingFunc
class Tween {
private:
static inline Tween* head = nullptr;
static inline Tween* last = nullptr;
static inline uint32_t frameRateTimer;
Tween* next;
public:
Tween(uint16_t fps = 30) {
setFps(fps);
if (Tween::head == nullptr) {
Tween::head = this;
}
if (last != nullptr) {
last->next = this;
}
last = this;
}
static void tick() {
Tween* current = Tween::head;
while (current != nullptr) {
current->update();
current = current->next;
}
}
///////
private:
uint16_t frameTime;
float dt;
uint32_t oldMillis;
float from;
float to;
float duration;
EasingFunc::eFunc easing = nullptr;
float progress;
bool isPlayingF;
bool triggerLastTick = false; // Флаг последнего тика
public:
float current;
void dtTick() {
uint32_t loopStartTime = millis();
dt = (loopStartTime - oldMillis) / 1000.0;
oldMillis = loopStartTime;
}
void update() {
if (millis() - frameRateTimer > frameTime) {
uint32_t now = millis();
dt = (now - oldMillis) / 1000.0;
oldMillis = now;
if (!isPlayingF && triggerLastTick) {
triggerLastTick = false;
current = to;
return;
}
if (!isPlayingF || easing == nullptr) return;
progress = constrain(progress + dt, 0, duration);
float normProgress = constrain(progress / duration, 0, 1);
current = Tween::lerp(from, to, easing(normProgress));
if (progress >= duration) {
current = to;
triggerLastTick = true;
isPlayingF = false;
}
frameRateTimer = millis();
}
}
float getProgress() {
return constrain(progress / duration, 0, 1);
}
void start(float from, float to, uint16_t duration, EasingFunc::eFunc easing) {
current = from;
if (from == to) {
current = to;
isPlayingF = false;
triggerLastTick = true;
return;
}
this->from = from;
this->to = to;
this->duration = duration / 1000.0;
this->easing = easing;
progress = 0;
oldMillis = millis();
isPlayingF = true;
triggerLastTick = false;
}
void resetToStart() {
progress = 0;
}
void stop() {
isPlayingF = false;
current = to;
triggerLastTick = true;
}
bool isPlaying() const {
return isPlayingF || triggerLastTick; // Учитываем последний тик
}
void setFps(uint16_t fps){
frameTime = 1000 / fps;
}
float getFrom() const {
return from;
}
float getTo() const {
return to;
}
static float integrateEasing(EasingFunc::eFunc easing, int steps = 100) {
float sum = 0;
for (int i = 0; i <= steps; ++i) {
float t = i / (float)steps;
sum += easing(t);
}
return sum / (steps + 1); // Среднее значение функции
}
static float lerp(float a, float b, float t) {
return a + (b - a) * t;
}
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;
// }
};