Tweeny Manual

This document is the manual for Tweeny. It walks you through all the important steps when creating and controlling tweens.

# Creating a tween

Tweeny can interpolate a single value, a set of values and a set of values with different types. For each of these cases, you create a tween using the same method: tweeny::from. The argument types you pass to it defines the tween itself which in turn defines argument number and types for tween::to, tween::during and tween::via, as well as the callback argument types.

Here is how you create a tween:

// Creates a single-valued tween
auto tween = tweeny::from(0);
// Creates a multi-valued tween
auto tween2 = tweeny::from(0, 1, 2);
// Creates a multi-value heterogeneous tween
auto tween3 = tweeny::from(0, 'a', 1.0f);

# Adding tween points

A tween without a target value does nothing. To add a point to a tween, use the method tween::to. Since tweeny::from returns the tween instance itself, you can chain both calls, forming the following:

// For a single value
auto tween = tweeny::from(0).to(100);
// For multiple values
auto tween = tweeny::from(0, 'a').to(10, 'z');

Notice how arguments to tween::to were of the same type of the arguments to tweeny::from.

# Specifying durations

A tween needs a duration between each point. This duration unit is a unsigned integer that can represent anything you want. Usually I use it as milliseconds (this is relevant when stepping a tween). To specify the duration, call tween::during after tween::to:

auto tween = tweeny::from(0).to(100).during(100);

When you have a multivalued tween, you can either pass one single duration for all the values or specify a value for each point:

auto tween = tweeny::from(0, 1, 2).to(3, 4, 5).during(50, 100, 200);

The total duration from the starting point `(0, 1, 2)` to the next point `(3, 4, 5)` is 200, but each value will reach their target at different times.

To specify the same time for each value, pass a single value for tween::during:

auto tween = tweeny::from(0, 1, 2).to(3, 4, 5).during(200);

# Changing easing functions

Easing functions control the interpolation values between each point. Given a percentage `p`, initial value `a` and final value `b`, a easing function will return a value between `a` and `b` corresponding to that `p`. For instance, the common implementation of a linear easing function is the following:

int linear(float p, int a, int b) {
return (b-a)*p + a;
}

By default, tweens use a linear easing function to interpolate their values. You can change that, though: Tweeny has 30 easing functions that you can specify using tween::via function.

auto tween = tweeny::from(0).to(10).during(100).via(tweeny::easing::circularInOut);

The same rules of tween::during applies here: if you have multi-valued tweens, you can specify a different easing for each one or use the same for all of them:

using tweeny::easing;
auto tween = tweeny::from(0, 1, 2).to(3, 4, 5).during(200).via(easing::exponentialIn, easing::exponentialInOut, easing::backOut);

For a list of all available easings, consult the modules page. http://easings.net has a nice visualization of those easing curves.

You can specify custom easing functions if a different behavior is needed, by passing any callable type to tween::via conforming to the `T ease(float p, T begin, T end)` prototype and returning the corresponding value.

auto tween = tweeny::from(0).to(100).during(100).via([](float p, int a, int b) { return (b-a)*p + a; } );

To a multi type tween, you need to make sure that easing arguments conform to their type:

auto tween = tweeny::from(0, 1.0f).to(100, 200.0f).during(100)
.via([](float p, int a, int b) { return (b-a)*p + a; }, [](float p, float a, float b) { return (b-a)*p + a; });

Beware that when using integral types most easing functions will not round but truncate their results. This leads to strange behaviors such as the tween reaching its final value only when it its 100% but staying in its initial value for a long percentage portion. You can use floating point values and round them to obtain smoother results. easing::linear does this by default for integral types, but other easings don't.

# Multi point tweens

Tweens can have multiple points: a sequence of values that will be reached in order. For instance, you might want to start from 0, reach 100 during 500ms through a easing::linear easing, then reach 200 during 100ms through a easing::circularOut easing.

To allow for that, each call to tween::to adds a new tweening point. Calls to tween::during and tween::via always refer to the last added point:

auto tween = tweeny::from(0)
.to(100).during(500) // 0 to 100 during 500
.to(200).during(100).via(easing::circularOut); // 100 to 200 during 100 via circularOut

Stepping and seeking works transparently for the user, regardless of how many tween points there are. This means that Tweeny will automatically manage switching from one point to another when using tween::step and tween::seek.

# Stepping, seeking and jumping.

After setting up points, durations and easings, a tween is ready to interpolate. There are three main ways to do that and we are going to cover them in this section.

The first one is stepping. It is used to move the tween forward by a delta amount, which can be either specified in duration units or percentage. Stepping is particularly useful when you are in a event/rendering loop and has access to the delta time between frames:

auto tween = tweeny::from(0).to(100).during(1000);
while (!done) {
tween.step(dt);
}

Passing a integral quantity (integers) to tween::step will step it in duration units. Passing a float value will step it by a percentage (ranging from 0.0f to 1.0f).

You can set a tween to go backwards, so that it steps in reverse. To to that, use tween::backward: each tween::step call will decrease a tween time until it reaches 0. To make it go forward again, use tween::forward. Tween direction makes no difference when seeking or jumping.

The second one is seeking. Seeking is useful if you need the tween to move to a specific point in time or percentage.

auto tween = tweeny::from(0).to(100).during(1000);
tween.seek(0.5f);

The same value type rules of tween::step applies: a float value means a percentage and an integral value means duration.

The third one is jumping. Jumping is useful to seek to a specific tween point, when you have Multi point tweens .

auto tween = tweeny::from(0).to(100).during(100).to(200).during(100);
tween.jump(1);

tween::step, tween::seek and tween::jump both returns the result of their action. The return type varies according to the tween type according to these rules:

- If the tween has a single value, it will yield that value directly:
  auto tween = tweeny::from(0).to(100).during(100);
  int value = tween.step(10);
- If the tween has multiple values of the same type, it will yield an array with those values:
  auto tween = tweeny::from(0, 1).to(2, 3).during(100);
  std::array<int, 2> v = tween.step(10);
- If the tween has multiple types, it will return a tuple:
  auto tween = tweeny::from(0, 1.0f).to(2, 3.0f).during(100);
  std::tuple<int, float> v = tween.step(10);

# Callbacks

Tweeny lets you specify seeking and stepping callbacks so that actions can executed in specific points (e.g, playing a sound when a tween reaches a frame). tween::onStep add a function that will be called whenever a tween steps whereas tween::onSeek will add a function to be called when it seeks. Although stepping is resolved in terms of seeking, tween::step it will not trigger seek callbacks.

Callbacks can be of three different types:

- Accept the tween and its current values. Useful if you want access to tween values and need to control the tween instance:
  bool stepped(tween<int, int> & t, int x, int y);
  auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);
- Accept only a tween, useful if the values itself are not interesting but you need to control tween behavior:
  bool stepped(tween<int, int> & t);
  auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);
- Accept only tween values, if you just want tween values:
  bool stepped(int x, int y);
  auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);

The return type of a callback is always boolean. If it returns true, it will be dismissed and removed from the callback list. Returning false keeps the callback in the queue:

bool stepped(int x, int y) {
printf("x: %d, y: %d\n", x, y);
if (x == y) return true;
return false;
}
auto tween = tweeny::from(0, 0).to(100, 200).during(100).onStep(stepped);

All callable types can be used as a callback, as long as they conform to the interface.

struct ftor {
bool operator()(int x, int y) { return false; }
};
auto tween = tweeny::from(0, 0).to(100, 200).during(100);
tween.onStep([](int, int) { return false; }); // lambdas
tween.onStep(ftor()); // functors

The loop has some nice ways of using callbacks.

This covers all the basics steps of using Tweeny. There is more to learn though, take a look at the demo repository to see more. Consult the API of the tween class to see all its methods and more examples within.

I hope you have fun using Tweeny.