Tween library for Arduino with Robert Penner's easing functions
If you have already installed this library, please follow:
- Cloned from GitHub (manually): Please install dependent libraries manually
- Installed from library manager: re-install this library from library manager
- Dependent libraries will be installed automatically
This library is consists of three classes and each Transition
has easing function:
Transition
: a transition of target value (with Easing)Sequence
: a series of transitions (with offset)Timeline
: a collection of sequences
Tween::Timeline timeline; // create timeline
timeline.add(target) // add sequence to timeline
.init(0) // init target value (optional)
.offset(1000) // delay start without transaction (optional)
.then(10, 5000) // add transaction (change linearly)
.hold(1000) // add transaction (stay on the same value)
.then<Ease::Sine>(0, 500); // add transaction with Easing
#include <Tween.h>
Tween::Timeline timeline;
float target = 0.f;
void setup() {
timeline.add(target) // target tweens
.init(0) // init target value (optional)
.offset(1000) // delay start 1000[ms] (optional)
.then(10, 5000) // to 10 in 5000[ms]
.then(5, 5000) // then to 5 in 5000[ms]
.hold(1000) // then stops 1000[ms]
.then(0, 5000); // then to 0 in 5000[ms]
timeline.start();
}
void loop() {
timeline.update(); // must be called to tween target
Serial.println(target); // target value tweens automatically
}
You can specify a easing type for each transition.
timeline.add(f)
.then<Ease::Sine>(10, 5000)
.then<Ease::Elastic>(5, 5000)
.hold(1000)
.then<Ease::Bounce>(0, 5000);
Please refer here if you are not familiar with the easing. If you haven't specify the easing type, default value is Ease::Linear
.
- BackIn, BackOut, BackInOut
- BounceIn, BounceOut, BounceInOut
- CircIn, CircOut, CircInOut
- CubicIn, CubicOut, CubicInOut
- ElasticIn, ElasticOut, ElasticInOut
- ExpoIn, ExpoOut, ExpoInOut
- LinearIn, LinearOut, LinearInOut
- QuadIn, QuadOut, QuadInOut
- QuartIn, QuartOut, QuartInOut
- QuintIn, QuintOut, QuintInOut
- SineIn, SineOut, SineInOut
// alias
using Back = BackInOut;
using Bounce = BounceInOut;
using Circ = CircInOut;
using Cubic = CubicInOut;
using Elastic = ElasticInOut;
using Expo = ExpoInOut;
using Linear = LinearInOut;
using Quad = QuadInOut;
using Quart = QuartInOut;
using Quint = QuintInOut;
using Sine = SineInOut;
You can use custom classes if you have implemented following operators.
operator+(const T&)
operator-(const T&)
operator*(const double)
If you have these operator overloads, you can use that variable completely as same as other built-in variables.
Please see custom_class
example for details.
// CAUTION: just a simplified operator overloads
struct Vec2 {
float x;
float y;
Vec2() : x(0), y(0) {}
Vec2(const float x, const float y) : x(x), y(y) {}
Vec2 operator+(const Vec2& rhs) const {
return Vec2(x + rhs.x, y + rhs.y);
}
Vec2 operator-(const Vec2& rhs) const {
return Vec2(x - rhs.x, y - rhs.y);
}
Vec2 operator*(const double f) const {
return Vec2(x * f, y * f);
}
};
Tween::Timeline timeline;
Vec2 v;
void setup() {
timeline.add(v)
.then(Vec2(10, 8), 5000)
.then(Vec2(5, 10), 5000)
.hold(3000)
.then<Ease::Bounce>(Vec2(0, 0), 7000);
timeline.start();
}
void loop() {
timeline.update();
}
You can add transitions to your sequence dynamically like this:
float a = 0;
timeline.add(a).init(0).then(5, 1000);
timeline.start();
// do some stuff...
// dynamically append transition to sequence of "a"
timeline.append(a, 10, 5000);
This is same as following manual operation:
timeline[a].then(0, 5000);
timeline.update_duration();
See dynamic_append
example for the details.
There are 3 play mode for the Timeline
.
timeline.mode(Tween::Mode::ONCE); // default: stop timeline if finished
timeline.mode(Tween::Mode::REPEAT_TL); // repeat whole timeline if finished
timeline.mode(Tween::Mode::REPEAT_SQ); // repeat each sequence if finished
You can choose if you automatically erase the each sequence. This is not affected by timeline mode. If you choose to erase the sequence automatically, it will be erased after the first loop is finished. The default value is false
.
timeline.add(v, true) // erase this sequence automatically (default: false)
.then(10, 5000)
.then(0, 5000);
Offset is added only once in the begging of the timeline. Offset behaves differently especially based on the REPEAT_TL
and REPEAT_SQ
mode.
REPEAT_TL
: Offset is always added in every loopREPEAT_SQ
: Offset is added only once in the beggining (not included in loop)
Timeline timeline;
float value[5];
for (size_t i = 0; i < 5; ++i) {
timeline.add(value[i])
.offset(i * 1000)
.then(3, 1000)
.hold(2000);
}
template <typename T>
Sequence<T>& add(T& target, const bool b_auto_erase = false);
template <typename T, typename EasingType = Ease::Linear, typename U = T>
void append(const T& target, const U& to, const double in);
template <typename T>
void append(const T& target, const double in);
void update_duration();
void start();
void restart();
bool update();
void clear();
void mode(const Mode m);
Mode mode() const;
void auto_erase(const bool b);
size_t size() const;
template <typename T>
Sequence<T>& operator[](const T& t);
Timeline
is derived from FrameRateCounter. So its methods to control timeline are also available. Some useful methods are listed below.
virtual void start(); // overridden by Tween::Timeline
virtual void stop();
virtual void play();
virtual void pause();
virtual void restart(); // overridden by Tween::Timeline
virtual void clear(); // overridden by Tween::Timeline
void startFromSec(const double from_sec);
void startForSec(const double for_sec, const bool loop = false);
void startFromForSec(const double from_sec, const double for_sec, const bool loop = false);
bool isRunning() const;
bool isPausing() const;
bool isStopping() const;
double sec(); // get current time of timeline
template <typename U = T>
auto init(const U& to)
-> typename std::enable_if<std::is_convertible<U, T>::value, Sequence<T>&>::type;
template <typename EasingType = Ease::Linear, typename U = T>
auto then(const U& to, const double in = 0)
-> typename std::enable_if<std::is_convertible<U, T>::value, Sequence<T>&>::type;
Sequence<T>& hold(const double in);
Sequence<T>& offset(const double ms);
MIT