TweenX

TweenX is a cross-platform tween library for Haxe. It enables you to specify the movement destination of the object and make it motion.

About version 1.0

The biggest change between version 0.0 and 1.0 is the separation of TweenXCore for core functions such as easing.

Using TweenXCore, you can write motion in a way that is more flexible, faster to run, and more platform-independent.

TweenX is now a library that extends TweenXCore and handles tweening in a way similar to traditional libraries, including Tweener.

However, the traditional way has many problems, and I recommend using TweenXCore without TweenX.

Benchmark

I measured the FPS when tweening 250,000 objects on Flash platform.

result

It is faster to operate the object with TweenXCore alone than with TweenX.

Installation

You can easily install TweenX by using haxelib. Just type the following command on the console.

haxelib install tweenx

The installed libraries can be used by compiling with flags of -lib tweenx and -lib tweenxcore.

Haxe version

The version 1.0 of TweenX supports Haxe 3.2.1 or later.

Tutorial

Normal tween

By using TweenX, you can easily express the movement of an object.

//...
import tweenx909.TweenX;

class Main extends Sprite {
    //...
    public function new() {
        //...
        // Move the x coordinate of square to 360
        TweenX.to(square, {x:360});
        //...
    }
}

The to function can move multiple objects simultaneously by passing an array.

// Move x coordinates of 3 squares to 360
TweenX.to([square1, square2, square3], {x:360});

Method chain

In TweenX, you can specify values such as easing, playback time, delay time, and so on by method chain.

//...
import tweenx909.TweenX;
import tweenxcore.Easing;

class Main extends Sprite {
    //...
    public function new() {
        //...
        // After 0.5 seconds, in the easing decelerating exponentially over 1.2 seconds, move the square x coordinate to 360
        TweenX.to(square, {x:360}).delay(0.5).time(1.2).ease(Easing.expoInOut);
        //...
    }
}

The feature of the tween library is easy selection of the object speed change by specifying easing. TweenX’s 44 kinds of easing can be confirmed with the following sample.

using tweenx909.ChainX

A advantage of specifying the tween settings in the method chain is the powerful input completion. The method chain can be used not only for specifying time or easing. By declaring using tweenx909.ChainX;, you can set the various parameters of the tween using method chains.

//...
import tweenx909.TweenX;
import tweenxcore.Easing;

using tweenx909.ChainX;

class Main extends Sprite {
    //...
    public function new() {
        //...
        TweenX.to(square).x(360).rotation(360).scaleXY(0, 0).delay(0.5).time(1.2).ease(Easing.expoInOut);
        //...
    }
}

For example, on tween for Point, only x and y are autocompleted. On the other hand on tween for Sprite, in addition to them, other fields including scaleX, scaleY, and alpha are autocompleted.

Serial tween

By using TweenX.serial() you can easily express a continuous tween.

TweenX.serial([
    TweenX.to(square1).x(360).ease(Easing.expoOut),
    TweenX.to(square2).x(360).ease(Easing.expoOut),
    TweenX.to(square3).x(360).ease(Easing.expoOut),
]);

Parallel tween

To play multiple tweens at the same time, use TweenX.parallel().

TweenX.parallel([
    TweenX.to(square1).x(360).ease(Easing.expoOut),
    TweenX.to(square2).x(360).ease(Easing.expoOut),
    TweenX.to(square3).x(360).ease(Easing.expoOut),
]);

Lag tween

To play multiple tweens with time difference, use TweenX.lag().

TweenX.lag([
    TweenX.to(square1).x(360).ease(Easing.expoOut),
    TweenX.to(square2).x(360).ease(Easing.expoOut),
    TweenX.to(square3).x(360).ease(Easing.expoOut),
], 0.1);

Wait and Skip

To adjust the timing when grouping, use TweenX.wait() and skip().

TweenX.serial([
    TweenX.to(square1).x(360).ease(Easing.expoOut),
    TweenX.to(square2).x(360).ease(Easing.expoOut),
    TweenX.wait(0.3), // Wait 0.3 seconds.
    TweenX.to(square3).x(360).ease(Easing.expoOut).skip(), // Start the next tween without waiting for this tween.
    TweenX.to(square4).x(360).ease(Easing.expoOut),
]);

Repetition, yo-yo, zigzag

If you want to repeat the same motion, use repeat(). Furthermore, it is possible to control the behavior when repeating by zigzag(), yoyo(), interval() functions.

TweenX.serial([
    TweenX.to(square1).x(360).time(0.4).ease(Easing.quartOut).repeat(3),
    TweenX.to(square2).x(360).time(0.4).ease(Easing.quartOut).repeat(5).yoyo(),
    TweenX.to(square3).x(360).time(0.4).ease(Easing.quartOut).repeat(5).zigzag(),
]).repeat().interval(0.4);

Default value

Default values are provided for each setting such as time and ease. You can easily retrieve default values from TweenX.dumpDefaults() at any time, save them, and TweenX.setDefaults() to pass back.

The retrieved default values can be changed by method chains, or it can be passed as an argument to the serial, parallel, lag functions as default values only within the group

// Default values of each operation setting are as follows.
TweenX.defaultTime      = 0.3;
TweenX.defaultEase      = Easing.linear;
TweenX.defaultDelay     = 0;
TweenX.defaultRepeat    = 1;
TweenX.defaultYoyo      = false;
TweenX.defaultZigZag    = false;
TweenX.defaultInterval  = 0; // interval between each repetition
TweenX.defaultAutoPlay  = true; // Automatic start of tween

// Get current defaults
var defaults:DefaultsX = TweenX.dumpDefaults();

// Change contents of acquired value
defaults.ease(Easing.bounceOut).time(1);

// Set defaults
TweenX.setDefaults(defaults);

// Reset the default value to the initial.
TweenX.initDefaults();

// Apply default values to serialize group.
TweenX.serial([
    TweenX.to(square).x(360),
    TweenX.to(square).alpha(0),
], defaults);

Event handling

TweenX has two ways to handle events. One is to use on- functions. However, you can set one event handler with each on- functions. If you want to set multiple event handlers, use addEventListener.

// on- handlers are Void->Void
TweenX.to(square).x(360)
    .onDelay(_delay);          // Called when the value is not updated by the delay
    .onHead(_head);            // Called at the beginning of each repeat
    .onUpdate(_update);        // Called after updating the value
    .onFoot(_foot);            // Called at the end of each repeat
    .onInterval(_interval);    // Called when the value is not updated due to the interval
    .onRepeat(_repeat);        // Called before the next repeat starts
    .onRest(_rest);            // Called when the value is not updated due to the adjustment time
    .onFinish(_finish);        // Called when the tween finishes normally
    .onProgress(_progress);    // Called when tween playback has progressed
    .onPlay(_play);            // Called at the start of playback
    .onStop(_stop);            // Called when stopped

    // addEventListener's handlers are TweenX->Void
    .addEventListener(EventX.DELAY, delay);
    .addEventListener(EventX.HEAD, head);
    .addEventListener(EventX.REPEAT, repeat);
    .addEventListener(EventX.FOOT, foot);
    .addEventListener(EventX.UPDATE, update);
    .addEventListener(EventX.INTERVAL, interval);
    .addEventListener(EventX.REST, rest);
    .addEventListener(EventX.FINISH, finish);
    .addEventListener(EventX.PLAY, play);
    .addEventListener(EventX.STOP, stop);

Play, Stop, Fast Forward, Reverse Play

With TweenX, you can stop the tween, play from the middle, fast forward, rewind, and freely control it as if you were manipulating the video. Motions are played at the same start and end positions regardless of how many times playback is done. In other words, the display will not be disturbed by repeatedly playing the tween.

tween.stop();

tween.play();

tween.goto(0.1);

tween.goto(0, true);

// Get current playing time
tween.currentTime;

// Get the time it takes to play the tween from beginning to end
tween.totalTime;

// Fast forward
tween.timeScale = 8;

// Reverse play
tween.timeScale = -1;

// Change the playback speed of the whole TweenX
TweenX.topLevelTimeScale = 0.5;

Relative value tween

To set the destination as a relative value from the current location, use the - functions. To set it as a relative value from the start position, use the _- functions.

TweenX.serial([
    // The following three tweens all behave identically.

    // Tween by absolute value.
    TweenX.serial([
        TweenX.to(square).xy(360,   0),
        TweenX.to(square).xy(360, 360),
        TweenX.to(square).xy(  0, 360),
        TweenX.to(square).xy(  0,   0),
    ]),
    TweenX.wait(0.5),

    // Tween with relative value from current position.
    TweenX.serial([
        TweenX.to(square)._xy(360,   0),
        TweenX.to(square)._xy(360, 360),
        TweenX.to(square)._xy(  0, 360),
        TweenX.to(square)._xy(  0,   0),
    ]),
    TweenX.wait(0.5),

    // Tween with relative value from start position.
    TweenX.serial([
        TweenX.to(square).__xy( 360,    0),
        TweenX.to(square).__xy(   0,  360),
        TweenX.to(square).__xy(-360,    0),
        TweenX.to(square).__xy(   0, -360),
    ]),
]).delay(0.5);

Function tween

To execute a function while making tweening, use tweenFunc1(), tweenFunc2(), tweenFunc3(), tweenFunc4() or tweenFunc().

function draw(x:Float, size:Float) {
    graphics.lineStyle(1, 0x335F73);
    graphics.drawCircle(x, 200, size);
}

TweenX.tweenFunc2(draw, 10, 10, 300, 100).time(0.5).ease(Easing.quadIn);

The numbers 1, 2, 3, 4 correspond to the number of Floats to be changed. If you want to tween values other than Float, or if the number of values you want to tween exceeds 4, use the tweenFunc() function.

not Float tween

TweenX supports eight types of tweening besides tweening of Float type values. They are Boolean, Array, RgbColor, ArgbColor, HsvColor, AhsvColor, Quake and Timeline.

RgbColor, HsvColor tween

Color tweens are based on RGB, ARGB, HSV or AHSV.

function draw(x:Float, y:Float, color:Int) {
    graphics.beginFill(color);
    graphics.drawRect(x, y, 8, 40);
}

TweenX.serial([
    TweenX.tweenFunc(draw, [0, 100, RgbColor.of(0x3373EE)  ], [380, 100, RgbColor.of(0xEE7333)  ]),
    TweenX.tweenFunc(draw, [0, 180, HsvColor.of(0x3373EE)  ], [380, 180, HsvColor.of(0xEE7333)  ]),
    TweenX.tweenFunc(draw, [0, 260, new HsvColor(0,0.7,0.9)], [380, 260, new HsvColor(2,0.7,0.9)]),
]);

For tweening based on values of type RgbColor, ArgbColor, HsvColor, or AhsvColor, an integer value of 0x(AA)RRGGBB format is output.

Array tween

Each element can be moved by tweening the array. However, the array must consist of tweenable values.

var square = new GradientSquare(
    [0x2C3E50, 0xE74C3C, 0xECF0F1],
    [0,        0.5,      1,      ],
    [0,        64,       255,    ]
);
addChild(square);
square.x = square.y = CELL_SIZE * 6;

TweenX.to(
    square,
    {
        colors:[HsvColor.of(0x08A689), HsvColor.of(0xC7D93D),  HsvColor.of(0xE9F2A0)],
        alphas:[1,                     0,                      0.5,                 ],
        ratios:[0,                     192,                    255,                 ]
    }
).time(2).ease(Easing.expoInOut).onUpdate(square.update);

Boolean tween

For Boolean tweens, false is assumed to be 0 and true is assumed to be 1, tweening is performed. 0 or less is regarded as false, and a value exceeding 0 is regarded as true and reconverted to Boolean and output.

Quake

By tweening with QuakeX type value you can move the value while oscillating it.

TweenX.from(square, { x:180, y:180 });
TweenX.to(
    square,
    {
        x:new QuakeX(180, 80, Easing.linear),
        y:new QuakeX(180, 80, Easing.linear)
    }
).time(2);

Timeline tween

By setting it as a value to tween the Timeline, you can achieve a tween with a non-continuous value. For example, it can be used to realize animation by replacing multiple bitmap data.

var timeline = new Timeline();
timeline.add(walk0);
timeline.add(walk1);
timeline.add(walk2);
timeline.add(walk1);
TweenX.to(bitmap, {bitmapData: timeline}).time(1).repeat(0);

For each element of Timeline, not only BitmapData but also an various values can be set. The second argument specifies the weight to assign to each element.

Other tween

You can also make your own tweening for objects other than the above.

First, with reference to other not Float tween, create your own class that satisfies the condition of RuleX type and add a new rule using TweenX.addRule function.

TweenX.addRule(CustomRule);

Advanced content

It is not necessary to know the contents after this, but if you want to use TweenX more safely, more accurately, more conveniently it will be useful to read.

Manual update

By setting updateMode to MANUAL and calling manualUpdate for each frame you can control the timing of tween update by yourself.

//...
import tweenx909.TweenX;
import tweenx909.advanced.UpdateModeX;
//...

class Main extends Sprite {
    //...
    public function new() {
        //...
        TweenX.updateMode = UpdateModeX.MANUAL;
        addEventListener("enterFrame", onFrame);
        //...
    }

    function onFrame(e){
        TweenX.manualUpdate(1/60); // update all tween for 1/60 of a second.
    }
}

Initialization of tween

TweenX prohibits changing the target position and setting after the tween has been initialized in order to eliminate the occurrence of bugs with low repeatability and unintended behaviors.

Initialization of the tween will be done at the earliest timing of the following.

  • Calling play, goto or update

  • First update after tween is defined

In the initialization of tween, the following is done.

  • Determining the start position of a tween

  • Fixing target position and each set value (ease, time, repeat, yoyo, zigzag, intarval, delay)

  • Starting tweens of which autoPlay set to true

If you try to change the setting or target position after the tween has been initialized, an execution error will occur. At first glance, it seems to be disadvantageous that setting and destination position can not be changed, but once the tween defined is unchanged, it brings great advantage. The tween defined by TweenX behaves like a movie . In other words, even if you play a tween from the middle, reverse play, fast forward, or play back again after a while, the tween will not collapse.

And another advantage of having tweening unchanged is the description of the tween start position.

Start position

The start position of the tween is basically the target value when the initialization was done. However, if the same tween has already been defined in the same frame, the start position will be set as the continuation of that tween. For this reason TweenX does not need to write the same value twice. Of course the tween will not be affected by the target’s playback state, so you do not need to take extra care about moving the target.

var defaults = TweenX.dumpDefaults();
defaults.time(1).ease(Easing.quartOut);

TweenX.serial([
    // Since there is no tween defined from the last update,
    // starting with the coordinates when the tween was initialized
    TweenX.to(square).x(360).y(  0),

    // The next tween is from x: 360, y: 0
    TweenX.to(square).x(360).y(360).yoyo().repeat(2),

    // As it comes back by yoyo, the next tween is from x: 360, y: 0
    TweenX.to(square).x(  0).y(360).zigzag().repeat(3),

    // The next tween is from x: 0, y: 360
    TweenX.to(square).x(  0).y(  0),
], defaults).repeat();

The point to note here is that the starting position is determined at the time of tween initialization. Since the determination of the tween start position is done based on the defined order, if you reverse the order of playback and definition, non-continuous tweening is generated as follows.

TweenX.to(square).x(180).delay(2);
TweenX.to(square).x(360).delay(1);

The starting position can also be explicitly specified using the TweenX.from() function.

Free memory

How to prevent memory leaks when dealing with tweening libraries is very important. The method in TweenX is simple. Please stop the unnecessary tweens. Stopped tween can be subject to garbage collection because there is no reference from TweenX’s library. If it is a tween with a short playing time, it stops at the same time as playback ends. However, please stop explicitly when an unrestricted repeating tween with repeat set to 0 or a tween with long playing time becomes unnecessary.

Another reason that causes memory leak is when manualUpdate is not called even though updateMode is set to MANUAL. If manualUpdate is not called, a large amount of tween waiting for initialization may accumulate, causing memory leak. When updateMode is set to MANUAL, please call manualUpdate on a regular basis.

Debug mode

By adding the following compiler flags, information on TweenX is output.

-D tweenx_debug

The content is information on the operation of all tweens as follows.

...
Main.hx:171: Tween_20(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) UPDATE
Main.hx:171: Tween_21(generated at TweenXPlayer/change()[TweenXPlayer.hx:98]) UPDATE
Main.hx:171: Tween_23(generated at TweenXPlayer/change()[TweenXPlayer.hx:105]) UPDATE
Main.hx:171: Tween_24(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) UPDATE
Main.hx:171: Tween_20(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) UPDATE
Main.hx:171: Tween_20(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) FOOT
Main.hx:171: Tween_20(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) FINISH
Main.hx:171: Tween_20(generated at TweenXPlayer/change()[TweenXPlayer.hx:102]) STOP
Main.hx:171: Tween_21(generated at TweenXPlayer/change()[TweenXPlayer.hx:98]) UPDATE
Main.hx:171: Tween_21(generated at TweenXPlayer/change()[TweenXPlayer.hx:98]) FOOT
Main.hx:171: Tween_21(generated at TweenXPlayer/change()[TweenXPlayer.hx:98]) FINISH
...

If you do not need information on update of each tween, add it as follows.

-D tweenx_debug_hide_update

Notes on grouping

The serial, parallel, lag function adjusts the internal tween delay and rest time during grouping to achieve continuous tweens by aligning the lengths of all the tweens. For this reason, it is recommended to use the TweenX.func() function rather than setting an event handler when you want to process at the timing when a specific tween starts.

Easing setting for the group

In TweenX, easing can be set not only for individual tweens but also for the tween grouped by serial, parallel, lag functions.

TweenX.serial([
    TweenX.to(square).time(0.48).x(120),
    TweenX.to(square).time(0.80).x(240).y(260),
    TweenX.to(square).time(0.48).x(360)
]).ease(Easing.bounceInOut);

Group easing is Easing.linear unless you explicitly change it. It is not influenced by the default value to avoid duplicate easing being specified.