Tween is a C++ library providing an implementation for tweening. In details, this library allows to interpolate the intermediate values between two given values during a time interval. This practice is well used in animation and is widely popular in the context of ActionScript/Flash games and websites. The goal of this library is to provide similar functionalities to C++ programs.
Making a variable to vary from a original value to a final value following a predefined function is something recurrent in programming and especially during the development of games. As far as we know, the only free C++ library providing this functionality is cpptweener, a port of the tweener library. Unfortunately, even if cpptweener is an accurate port of the ActionScript tweener library, she lacks several functionalities.
Our implementation is inspired from the aforementioned cpptweener and tweener libraries. Indeed, the same terminology will be used and the equations of Penners are also implemented. claw::tween provides the following functionalities:
This section presents some simple programs to show the usage of the claw::tween library.
The following C++ program changes the value of a given variable from its initial value to a target value using a linear interpolation of the values in-between.
In the above function a variable
x is created with an initial value. The tweener is then created:
Since there is only a single value to interpolate, a
single_tweener is used. Let's observe the detail of the constructor's parameters:
The first parameter is the variable whose value is interpolated. The second parameter is the value that must be assigned to val at the end of the interpolation. Then the third parameter is the total duration of the interpolation. The unit can be whatever the user wants (seconds, milliseconds, …) as long as this is the same unit used for the updates. Finally, the fourth parameter is the function used to compute the intermediate values. See Easing functions for details about those functions.
The next part of the example updates the tweeners until the end value is reached.
The parameter of the
update function is the elapsed time since the last update. Here the loop does ten iterations and produces the following output:
10.5 11 11.5 12 12.5 13 13.5 14 14.5 15
The following C++ program changes the value of several variables from their initial values to a target value using a linear interpolation of the values in-between. Since we do not want to manage each tweener individually, we will use a
tweener_group to manage them.
Here there are several values to interpolate simultaneously. Instead of updating each tweener individually, they are inserted into a
tweener_group that will manage them. One can notice that claw::tween::tweener_group is also a tweener, thus we insert groups inside groups.
In the previous example all the member variables of
coord are public, thus they can be passed by reference to the constructor of
single_tweener. Unfortunately in most real-life situations the member variables are not public and those values are modified using setters. In this situation, one can use the second constructor of
This constructor accept a callback function as the fourth parameter. This function, whose signature must be
void (double), is called at each update with the interpolated value as its only parameter.
Here is a modification of the previous example where setters are used to update the values of the
coord. The callback is created using boost::bind to create a function with the adequate signature.
The library provides three tweener classes to manage tweeners, named
tweener_sequence. Each one fills a particular need described in the following sections.
The tweener interface, as described below, is quite simple:
The tweener library use two functions to manage the tweeners. First, the
bool is_finished() const must return true if and only if the final value has been reached. Then,
double update(double) is used to update the intermediate values, where the single argument is the amount of time since the last update or since the construction of the tweener. This function returns the amount of dt not used in the update. For example, if a tweener is at 1 time unit from the end of the interpolation and
update(1.5) is called on this tweener, then 0.5 is returned. Indeed, only 1 of the 1.5 available units have been used to reach the end of the interpolation.
When a tweener is finished, all the functions passed to
void on_finished( finish_callback ) are called in sequence.
The claw::tween::single_tweener object is the class to use to make one value to vary from a source value to a final value in a given amount of time and according to a given easing function. The interface is described below:
The default behavior of the single_tweener is to use a callback function to send the new value to the caller at each update. Let's have a look at the following constructor.
The two first arguments defined the value returned by the tweener respectively at the beginning and the end of the interpolation. The third parameter is the total duration of the interpolation. The unit can be whatever the user wants (seconds, milliseconds, …) as long as this is the same unit used for the updates. The fourth argument is the callback function called at each update. His signature must be
void (double), where the argument receive the current intermediate value. Finally, the fifth parameter is the function used to compute the intermediate values. See Easing functions for details about this topic.
In the situation where the interpolation is done on a known variable, one would have to provide a callback function to assign the intermediate values to the variable. In order to ease the use of tweeners for this kind of situation, an other constructor is defined:
The difference with the aforementioned constructor is that there is no callback function to provide. Here, the first parameter is the variable whose value is interpolated. Its initial value is taken for the initial value of the interpolation. The created tweener will manage the assignment of the intermediate value to val.
In other words, the following program:
is completely equivalent to this more concise program:
void on_finished() function allows to insert a callback that will be called when the tweener finishes, during a call to
Once that single_tweener is understood, the other tweener classes are quite simple. The claw::tween::tweener_group class is a tweener class that executes several tweeners simultaneously. Its interface is defined as follows:
tweener_group class does not compute values by itself but forwards the call to
update(double) to other tweeners, thus allowing to play several tweeners in parallel.
bool is_finished() function returns true when all the tweeners of the group are finished. Also, tweeners can be inserted in a
tweener_group at any time.
void on_finished() function allows to insert a callback that will be called when the last tweener in the group finishes, during a call to
The claw::tween::tweener_sequence class is a tweener class that executes several tweeners in a row. Its interface is defined as follows:
tweener_sequence class does not compute values by itself but forwards the call to
update(double) to the current active tweener, splitting the argument value among several tweeners if needed.
bool is_finished() function returns true when all the tweeners of the sequence are finished. Also, tweeners can be inserted in a
tweener_sequence at any time.
void on_finished() function allows to insert a callback that will be called when the last tweener in the sequence finishes, during a call to
The easing functions define how the intermediate values are computed during the interpolation. For example, when tweening a value from 0 to 1 during 1 second using a linear interpolation, the value at 0.5 second must be 0.5. But when using a quadratic interpolation the value at this same date must be 0.25. The goal of an easing function is to compute those intermediate values according to a predefined curve.
An easing function is a function whose signature is
double (double) verifing the following contract:
The second criteria may need more explainations. For example, if the tweener's start value is v1 and its last value is v2. Then a return value of 0 means that the intermediate value set by the tweener must be v1, while a return value equal to 1 corresponds to an intermediate value equal to v2. In other words, a return value of x implies an intermediate value set by the tweener to v1 + x × (v2 - v1).
There are typically three ways to apply an easing effect: when reaching the final value (ease-in), when leaving the initial value (ease-out), or in both situations (ease-in-out).
One can observe that the ease-out can be computed from the ease-in value, and ease-in-out can be computed from ease-in and ease-out. The goal of the claw::tween::symmetric_easing class is to define the ease-out and ease-in-out functions given the ease-out-function.
This class is defined as:
Given a function
double f(double) verifying the easing contract, then
symmetric_easing<f> provides the following implementations:
1 - ease_in(1 - t),
ease_in(2 * t) ÷ 2if t is less than 0.5,
0.5 + ease_out(2 * t - 1) ÷ 2otherwise.
The following easing classes are implementations of the
symmetric_easing class in the library.
|Easing Class and Ease-In Equation||Ease-In||Ease-Out||Ease-In-Out|
f(t) = t² × (2.70158 × t − 1.70158)
f(t) = 1 − √(1 − t²)
f(t) = t³
f(t) = −210 × (t − 1) × sin(((t − 1) − 0.3 ÷ 4) × 2 × π ÷ 4)
f(t) = t
f(t) = 0
f(t) = t²
f(t) = t⁴
f(t) = t⁵
f(t) = 1 − cos(t × π ÷ 2)