Animation — Tweens and Timelines

This guide discusses how to use the Corona animation plugin to move, rotate, fade, or scale a display object/group over a specific period of time. It also outlines how to use timelines to construct intricate multi-interpolation animations across one or more display objects/groups.

Plugin Features

Tweens

A basic tween can be initiated using one of these functions:

The basic syntax for these functions is:

animation.to( target, properties, params )
animation.from( target, properties, params )

Tween Target

The first argument in either function, target, will most often be a display object or display group that you wish to animate. However, for more specialized cases, it can also be a RectPath point for quadrilateral distortion, a table of RGB+A color channels for a Paint fill, or a fill.effect property.

Object Properties

The second argument, properties, is a table of key-value pairs. Inside this table, specify each desired property to change along with its final value (starting value if using animation.from()).

Interpolation Properties (Keys) Description
movement x, y Moves an object to/from a specific x or y coordinate.
rotation rotation Rotates an object to/from an angle to another.
fading in/out alpha Fades an object to/from an alpha value to another.
scaling up/down xScale, yScale Scales an object to/from a specific x ratio or y ratio.
font size size Applies only if target is a TextObject. This will tween the font size of the text object.
resizing width, height Resizes an object to/from a specific width/height to another.
distortion x1, y1, x2, y2, x3, y3, x4, y4 Applies only if target is a RectPath, applicable to a ShapeObject. See here for more information.
color channels r, g, b, a Applies only if target is the .fill table of a ShapeObject.
fill effect (various) Applies only if target is an object’s fill.effect property. In this case, the property (key) indicates an effect property associated with the specific filter effect. See here for details on which filter parameters apply to each filter effect.
anchor point anchorX, anchorY Shifts the object’s x or y anchor point.
mask position maskX, maskY For a masked image/group, shifts the mask’s x or y position.
mask scale maskScaleX, maskScaleY For a masked image/group, shifts the mask’s x or y scale ratio.

Some objects will not behave as you may expect during or following a tween. For instance, many widgets do not support scaling or post-declaration resizing, so you should not attempt to perform an xScale, yScale, width, or height tween upon them. Another example is physics bodies — if you scale or resize the physics object using a tween, the actual physics body will not scale along with that tween.

If in doubt, check the documentation associated with the object or library to confirm that it doesn’t have any property restrictions related to tweens.

Control Parameters

The third argument, params, is also a table of key-value pairs. Inside this table, specify the appropriate control parameters for the tween:

Control Description
time Specifies the duration of the tween in milliseconds.
delay Specifies the delay, in milliseconds, before the tween begins. Default is 0 (none).
easing Specifies the easing function used for the tween. See Easing Functions for details.
speedScale Adjusts the relative speed scale for the tween. This must be a positive number greater than 0. By default, the speed scale is 1 (normal speed). Values greater than 1 will increase the speed while values lower than 1 will decrease it.
tag String value which allows you to categorize tweens and control them together.
id Optional identification string to assign to the tween. This can be retrieved as obj.id from any of the tween event listener functions (see below).
iterations The number of times (integer) that the tween should repeat. Use 0 or -1 to make it repeat indefinitely.
reflect For tweens with multiple iterations, specifies whether alternate iterations are reflected (played in reverse). Default is false.
delta Specifies whether non-control parameters are interpreted as final ending values or as changes in value. The default is false.
constantRate + constantRateProperty If used, these two parameters must be specified together. See the documentation for details.

Easing Functions

By default, tweens occur at a consistent, linear rate of change from start to end. However, you may wish to use an easing effect to achieve a different result, for example, to make an object move quickly at the start and gradually slow down as it reaches its destination. This behavior can be achieved using an easing function in conjunction with the animation call.

To set an easing effect on a tween, simply provide the easing key in the params table with a value equal to one of the easing library functions. For example:

-- Tween the object using outward quadratic interpolation
animation.to( myObject,
    { y=100 },
    {
        time = 2000,
        easing = easing.outQuad
    }
)
-- Tween the object using inward and then outward exponential interpolation
animation.to( myObject,
    { y=100 },
    {
        time = 2000,
        easing = easing.inOutExpo
    }
)

Although the 40+ built-in easing functions will meet most developers’ needs, it’s possible to create custom easing functions and utilize them within tweens. See Custom Easing Functions below for details.

Tween Events

Tweens also support a full range of tween events as listed below. These should be specified as key-value pairs within the params table. When the event occurs, the associated listener function will receive a reference to the Tween object.

Event Parameter (Key) Description (Value)
start onStart Listener function to be called before the tween begins.
complete onComplete Listener function to be called after the tween completes.
pause onPause Listener function to be called when the tween is paused.
resume onResume Listener function to be called when the tween is resumed.
cancel onCancel Listener function to be called when the tween is cancelled.
repeat onRepeat Listener function to be called when the tween completes an iteration in a repeat cycle.
position change onPositionChange Listener function to be called when the tween has its playback position changed manually via object:setPosition() or animation.setPosition().

In the following example, the tweenListener() function will be called when the tween completes:

local myObject = display.newRect( 0, 0, 100, 100 )

local function tweenListener( obj )
    print( "Tween completed; ID: " .. obj.id )
end

animation.to( myObject,
    { alpha=0 },
    {
        time = 2000,
        id = "tween1",
        onComplete = tweenListener
    }
)

Timelines

A timeline is a powerful way to construct intricate multi-interpolation animations across one or more display objects/groups. They are constructed with the animation.newTimeline() command:

animation.newTimeline( timelineParams )

For this function, the timelineParams argument is a table which specifies the tweens, markers, and other parameters for the timeline.

Timeline Tweens

At the minimum, the timelineParams table must contain a child table, tweens, which contains all of the tweens that will be involved in the timeline:

local newTimeline = animation.newTimeline(
{
    tweens = {},
})

Inside the tweens table, individual tweens are configured via basic Lua tables that accept the following key-value pairs:

  • startTime — Optional number of milliseconds into the timeline progression at which the tween should start. Default is 0 (start of the timeline).
  • tween — Required table which configures the tween. This should be configured similarly to any basic tween (see Tweens above).
  • useFrom — Optional boolean property which, if set to true, will make the tween behave as if it were declared by animation.from() instead of animation.to().

For example, this tweens table configures two individual tweens for a timeline:

local newTimeline = animation.newTimeline(
{
    tweens = {
        { startTime=0, tween={ object1, { x=400 }, { time=4000, iterations=5, reflect=true } } },
        { startTime=1000, tween={ object1, { y=400 }, { time=4000, easing=easing.outQuad } } }
    },
})

Timeline Markers

For an added level of control, you can specify any number of markers within the timeline duration. These markers, specified within the optional markers table, allow you to specify jump-to points within the timeline. Each marker should be defined as a table containing the following properties:

  • name — A string name to associate with the marker. This name should be unique (you should not use duplicate marker names within the same timeline).
  • time — The number of milliseconds into the timeline progression at which to set the marker.
  • params — An optional table which can contain custom information; this table will be passed to the onMarkerPass listener function (details).

For example, this markers table configures three time markers for the timeline:

local newTimeline = animation.newTimeline(
{
    tweens = {
        { startTime=0, tween={ object1, { x=400 }, { time=4000, iterations=5, reflect=true } } },
        { startTime=1000, tween={ object1, { y=400 }, { time=4000, easing=easing.outQuad } } }
    },
    markers = {
        { name="marker_start", time=0 },    -- Start of the timeline
        { name="marker_2000", time=2000 },  -- 2 seconds into the timeline
        { name="marker_3000", time=3000 }   -- 3 seconds into the timeline
    },
})

Once configured, you can use a marker name to jump to its associated position. See object:setPosition() or animation.setPosition() for details.

Other Parameters

Timelines accept a variety of additional parameters (optional) which can be used for fine-tuned setup and control. These should be specified as key-value pairs within the timelineParams table.

Parameter (Key) Description
autoPlay Boolean value which, if true, makes the timeline play immediately. Default is false.
tag String indicating the timeline tag. The animation plugin can pause, resume, cancel, set the position, or change the speed scale of timelines sharing the same tag.
id Optional identification string to assign to the timeline. This can be retrieved as obj.id from any of the timeline event listener functions (see below).
delay Number indicating the delay, in milliseconds, before the timeline begins playing. Default is 0.
speedScale Adjusts the relative speed scale for the timeline. This must be a positive number greater than 0. By default, the speed scale is 1 (normal speed). Values greater than 1 will increase the speed while values lower than 1 will decrease it.
autoCancel Boolean value which, if true, causes all child tweens to be cancelled upon completion of the timeline. This should only be done if you don’t intend to replay the timeline again after its first play through. Default is false.

Timeline Events

Timelines also support a full range of timeline events as listed below. These should be specified as key-value pairs within the timelineParams table. When the event occurs, the associated listener function will receive a reference to the Timeline object.

Event Parameter (Key) Description (Value)
start onStart Listener function to be called directly before the timeline begins.
complete onComplete Listener function to be called after all tweens in the timeline complete or after the final marker in the timeline, whichever occurs first.
pause onPause Listener function to be called when the timeline is paused.
resume onResume Listener function to be called when the timeline is resumed.
cancel onCancel Listener function to be called when the timeline is cancelled.
position change onPositionChange Listener function to be called when the timeline has its playback position changed manually via object:setPosition() or animation.setPosition().
marker passed onMarkerPass Listener function to be called when a marker within the timeline is reached/passed. Instead of simply receiving a reference to the Timeline object, this function will receive a table containing a reference to the associated Timeline object (timeline), along with the name property and optional params table that was assigned to the specific marker.

In the following example, the timelineListener() function will be called when every iteration of every tween in the timeline completes:

local object1 = display.newRect( 50, 50, 100, 100 )

local function timelineListener( obj )
    print( "Timeline completed; ID: " .. obj.id )
end

-- Create a timeline object
local newTimeline = animation.newTimeline(
{
    tweens = {
        { startTime=0, tween={ object1, { x=400 }, { time=4000, iterations=5, reflect=true } } },
        { startTime=1000, tween={ object1, { y=400 }, { time=4000, easing=easing.outQuad } } }
    },
    id = "timeline1",
    onComplete = timelineListener
})

-- Set the timeline playing
newTimeline:resume()

Controlling Tweens/Timelines

Tweens and timelines can be controlled through various methods. You can either use a library command (through the animation plugin) or an object command on a Tween object or Timeline object.

One benefit of the library commands is that, depending on the parameter passed, you can affect multiple tweens and/or timelines with just one call (here, * indicates either pause, resume, cancel, setPosition, or setSpeedScale).

Parameter Syntax Scope
(none) animation.*() Affects all tweens/timelines.
tween reference (Tween) animation.*( tweenObject ) Affects the specified referenced tween (tweenObject).
timeline reference (Timeline) animation.*( timelineObject ) Affects the specified referenced timeline (timelineObject).
tag name (String) animation.*( "tagName" ) Affects all tweens/timelines sharing the same tag name.
object reference (DisplayObject) animation.*( DisplayObject ) Affects all tweens on the specified display object/group.

Any control method that targets a specific child tween within a Timeline is ignored. Timeline tweens are controlled by the parent timeline, so you should control the timeline itself. For instance, if a tween within a timeline is affecting an object named object1, you can not pause that specific tween by calling animation.pause( object1 ) this is because the timeline owns all of its child tweens and it should be treated as a collective animated sequence.

Tween/Timeline Status

If needed, you can get the status of a specific tween or timeline via the following calls:

Status Object Commands
paused/unpaused Tween:getIsPaused()  /  Timeline:getIsPaused()
current position Tween:getPosition()  /  Timeline:getPosition()
current speed scale Tween:getSpeedScale()  /  Timeline:getSpeedScale()
duration Tween:getDuration()  /  Timeline:getDuration()

Custom Easing Functions

If the built-in easing functions do not include a very specific interpolation pattern necessary for your project, it’s possible to create custom easing functions and utilize them as the easing property for a tween.

Custom easing functions should follow the pattern of other easing functions, such as that for easing.linear:

easing.linear = function( t, tMax, start, delta )
    return delta * t / tMax + start
end

Essentially, as long as the custom easing function can accept the t, tMax, start, and delta properties, any number which is output at the other end is valid (although usually it should return a number between 0 and 1).

Once you’ve written your easing function, simply reference it as the easing parameter for the tween. For example:

local myObject = display.newRect( 0, 0, 100, 100 )

local function myLinearEasing( t, tMax, start, delta )
    return delta * t / tMax + start
end

animation.to( myObject,
    { x=500 },
    {
        time = 2000,
        easing = myLinearEasing
    }
)
Note

Most easing functions are designed to return 0 when t=0, and 1 when t=1. However, this may not always be desirable. For instance, out-and-back easing functions such as easing.continuousLoop return 0 when t=0 but also return 0 when t=1. In other words, the end value is the same as the start value. If your custom easing function is like this, you must set easingEndIsStart = true as a parameter for the tween or it will misbehave upon completion and repeated iterations. For instance:

animation.to( myObject,
    { x=500 },
    {
        time = 2000,
        easing = myContinuousEasing,
        easingEndIsStart = true
    }
)