GithubHelp home page GithubHelp logo

tween.lua's Introduction

tween.lua

Build Status Coverage Status

tween.lua is a small library to perform tweening in Lua. It has a minimal interface, and it comes with several easing functions.

Examples

local tween = require 'tween'

-- increase the volume of music from 0 to 5 in 10 seconds
local music = { volume = 0, path = "path/to/file.mp3" }
local musicTween = tween.new(10, music, {volume = 5})
...
musicTween:update(dt)

-- make some text fall from the top of the screen, bouncing on y=300, in 4 seconds
local label = { x=200, y=0, text = "hello" }
local labelTween = tween.new(4, label, {y=300}, 'outBounce')
...
labelTween:update(dt)

-- fade background from white to black and foregrond from black to red in 2 seconds
-- Notice that you can use subtables with tween
local properties = {bgcolor = {255,255,255}, fgcolor = {0,0,0}}
local fadeTween = tween.new(2, properties, {bgcolor = {0,0,0}, fgcolor={255,0,0}}, 'linear')
...
fadeTween:update(dt)

Demo

There is a demo in the "demo" branch of this repo:

https://github.com/kikito/tween.lua/tree/demo

demo image

You will need LÖVE to execute the demo.

In the animation above, you can see how the user can move time "forwards or backwards" by pressing and releasing the space key.

Interface

Tween creation

local t = tween.new(duration, subject, target, [easing])

Creates a new tween.

  • duration means how much the change will take until it's finished. It must be a positive number.
  • subject must be a table with at least one key-value. Its values will be gradually changed by the tween until they look like target. All the values must be numbers, or tables with numbers.
  • target must be a table with at least the same keys as subject. Other keys will be ignored.
  • easing can be either a function or a function name (see the easing section below). It's default value is 'linear'
  • t is the object that must be used to perform the changes - see the "Tween methods" section below.

This function only creates and returns the tween. It must be captured in a variable and updated via t:update(dt) in order for the changes to take place.

Tween methods

local complete = t:update(dt)

Gradually changes the contents of subject to that it looks more like target as time passes.

  • t is a tween returned by tween.new
  • dt must be positive number. It will be added to the internal time counter of the tween. Then subject's values will be updated so that they approach target's using the selected easing function.
  • complete is true if the tween has reached its limit (its internal clock is >= duration). It is false otherwise.

When the tween is complete, the values in subject will be equal to target's. The way they change over time will depend on the chosen easing function.

If dt is positive, the easing will be applied until the internal clock equals t.duration, at which point the easing will stop. If it is negative, the easing will play "backwards", until it reaches the initial value.

This method is roughtly equivalent to t:set(self.clock + dt).

local complete = t:set(clock)

Moves a tween's internal clock to a particular moment.

  • t is a tween returned by tween.new
  • clock is a positive number or 0. It's the new value of the tween's internal clock.
  • complete works like in t:update; it's true if the tween has reached its end, and false otherwise.

If clock is greater than t.duration, then the values in t.subject will be equal to t.target, and t.clock will be equal to t.duration.

t:reset()

Resets the internal clock of the tween back to 0, resetting subject.

  • t is a tween returned by tween.new

This method is equivalent to t:set(0).

Easing functions

Easing functions are functions that express how slow/fast the interpolation happens in tween.

tween.lua comes with 45 default easing functions already built-in (adapted from Emmanuel Oga's easing library).

tween families

The easing functions can be found in the table tween.easing.

They can be divided into several families:

  • linear is the default interpolation. It's the simplest easing function.
  • quad, cubic, quart, quint, expo, sine and circle are all "smooth" curves that will make transitions look natural.
  • The back family starts by moving the interpolation slightly "backwards" before moving it forward.
  • The bounce family simulates the motion of an object bouncing.
  • The elastic family simulates inertia in the easing, like an elastic gum.

Each family (except linear) has 4 variants:

  • in starts slow, and accelerates at the end
  • out starts fast, and decelerates at the end
  • inOut starts and ends slow, but it's fast in the middle
  • outIn starts and ends fast, but it's slow in the middle
family in out inOut outIn
Linear linear linear linear linear
Quad inQuad outQuad inOutQuad outInQuad
Cubic inCubic outCubic inOutCubic outInCubic
Quart inQuart outQuart inOutQuart outInQuart
Quint inQuint outQuint inOutQuint outInQuint
Expo inExpo outExpo inOutExpo outInExpo
Sine inSine outSine inOutSine outInSine
Circ inCirc outCirc inOutCirc outInCirc
Back inBack outBack inOutBack outInBack
Bounce inBounce outBounce inOutBounce outInBounce
Elastic inElastic outElastic inOutElastic outInElastic

When you specify an easing function, you can either give the function name as a string. The following two are equivalent:

local t1 = tween.new(10, subject, {x=10}, tween.easing.linear)
local t2 = tween.new(10, subject, {x=10}, 'linear')

But since 'linear' is the default, you can also do this:

local t3 = tween.new(10, subject, {x=10})

Custom easing functions

You are not limited to tween's easing functions; if you pass a function parameter in the easing, it will be used.

The passed function will need to take 4 parameters:

  • t (time): starts in 0 and usually moves towards duration
  • b (begin): initial value of the of the property being eased.
  • c (change): ending value of the property - starting value of the property
  • d (duration): total duration of the tween

And must return the new value after the interpolation occurs.

Here's an example using LÖVE's Bezier Curve (you will need LÖVE for this example, but tween.lua does not need LÖVE in general).

local cubicbezier = function (x1, y1, x2, y2)
  local curve = love.math.newBezierCurve(0, 0, x1, y1, x2, y2, 1, 1)
  return function (t, b, c, d) return c * curve:evaluate(t/d) + b end
end

local label = { x=200, y=0, text = "hello" }
local labelTween = tween.new(4, label, {y=300}, cubicbezier(.35, .97, .58, .61))

Gotchas / Warnings

  • tween does not have any defined time units (seconds, milliseconds, etc). You define the units it uses by passing it a dt on tween.update. If dt is in seconds, then tween will work in seconds. If dt is in milliseconds, then tween will work in milliseconds.
  • tween can work on deeply-nested subtables (the "leaf" values have to be numbers in both the subject and the target)

Installation

Just copy the tween.lua file somewhere in your projects (maybe inside a /lib/ folder) and require it accordingly.

Remember to store the value returned by require somewhere! (I suggest a local variable named tween)

local tween = require 'tween'

You can of course specify your own easing function. Just make sure you respect the parameter format.

Specs

This project uses busted for its specs. In order to run them, install busted, and then execute it on the top folder:

busted

Credits

The easing functions have been copied from EmmanuelOga's project in

https://github.com/emmanueloga/easing

See the LICENSE.txt file for details.

Changelog

See CHANGELOG.md for a full list of changes.

tween.lua's People

Contributors

itsmapleleaf avatar kikito avatar mrcharles avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tween.lua's Issues

Tween individual tweens. Maybe groups of them.

I must consider that some people might want to use tweens with independent dts. Easy fix: add a :update method to the returned tweens. More involved solution: create / update groups of tweens.

Delay Call

Tween.lua is really awesome! Great work. I usually extend it with a 'delay call' interface function like this

function tween.delay(time, callback, ...)
    return tween.start(time, {}, {}, 'linear', callback, {...})
end

maybe there is a better way? Would it make sense to include this?

value change error

local tween = require("tween")

local obj = {x = 0}
local tw = tween.new(1.5, obj, {x = 1}, "inExpo")
tw:update(1 / 40)

print("x", obj.x)

tw:update(1 / 40)
print("x", obj.x)

print:

x 9.6154344052123e-005
x 0.00023039165028796

tween not working on audio mp3 files

I have an mp3 file I would like to tween. I am running Lua 5.4 and Love2d 11.3

I have the following setup in my main.lua file...

local tween = require 'libs/tween/tween'

-- increase the volume of music from 0 to 5 in 10 seconds
local music = {volume = 0, path = "audio/mp3/demo.mp3"}
local musicTween = tween.new(10, music, {volume = 5})

function love.load()
  -- other code...
end

function love.update(dt)
  musicTween:update(dt)
end

function love.draw()
  -- other code...
end

When I run my game, there are no errors, and no sound. but the rest of the game works. what am I doing wrong?

Many thanks

Parabolic arc

Is there any way to get this tween library to do a parabolic arc (like throwing a grenade)? I use this library pretty extensively in the Leadwerks engine and would love to be able to use it for a parabolic arc movement.

Apparent problem with colors

Have encountered problems with colors:

  1. There appears to be some linkage between changing colors in one event and another event. The order of events is critical to obtain the assign color.
  2. Some of the colors returned are less than zero. This doesn't seem to be a problem with 2DLove but Lua won't accept.
    I had to add checks like if r < 0 then r = 0 end etc. Not all 'easings' seem to produce these errors.

Another topic - text seems to be handled differently than other objects:

  1. Can't get tween.reset followed by a function call to text() to restart. Have to reload all the text settings.
  2. Can't change text="something" to change text as text moves aroung screen.
  3. The same code produces different color transitions for the text when using Love and Lua.

Sure would be nice to have some documentation in 'tween' to help find out what's going on.
Nice effects but struggling to control.
Best

Tweens using callbacks?

hey! I'm new to Lua, but was wondering if there's an easy way to get your tween library to just call a callback instead of applying the changes directly to a table? Perhaps the callback could have a few parameters, like:

percentComplete, delta

and percent = 0 is the start, and percent = 100 signifies the end of the tween, and returning false from the callback would cancel the tween?

I feel like I could mod the library to do this pretty easily, but was wondering what your thoughts were?

Thanks!

Backwards tween

Hello,
It might be intentional but tween:update doesn't return true when the tween reaches its original value when running backwards (aka passing a negative "dt").

Adding the following in Tween:set do the trick (line 340).

  return self.clock >= self.duration or self.clock == 0

Can you think of any possible side-effects if I run Tween with this hack?
Thanks

Issue when running demo

I get the following error when I attempt to run the demo project. I'm on macOS High Sierra 10.13.6 using Love 11.2

Error

main.lua:73: Invalid key constant:

Traceback

[C]: in function 'isDown'
main.lua:73: in function 'update'
[C]: in function 'xpcall'

Two tweens played one after the other

I have the following issue, I create all my tweens at startup like this:

local subject = { myVar = 0 }

local first  = tween.new(2, myVar, {myVar = 200})
local second = tween.new(2, myVar, {myVar = 400})

for i=1, 4 do
    local complete = first:update(dt)
    if complete then second:update(dt) end
   print(myVar)
end

I would expect:

100
200
300
400

But instead I get:

100
200
100
400

The problem is that since the tweens affect the same object and were created at the same time they always go back to the original state, when I just want them to "connect"

I know how the library works internally and that this is no simple change because you basically deepcopy the original table and use that as the base.

But for complex animations this is a needed feature, is this possible in a simple way?

Something like deepcopying the table on the first update of the tween

Note: Here I put two tweens but we are talking about many more, maybe a hundred, and most of them are repeated, modify really similar variables.

[suggestion] Curve-Bezier

In CSS there are not many easing curves, 5 or so. Instead it is pretty normal to use Bezier Curves to descrive a easing curve.

Bezier Curves were added to LÖVE in 0.9.0 in the love.math module (see love.math.newBezierCurve)
So I thought this would be easy to implement, and so it is! Here is my little implementation:

cubicbezier = function (x1, y1, x2, y2)
    local curve = love.math.newBezierCurve(0, 0, x1, y1, x2, y2, 1, 1)
    return function (t, b, c, d) return c * curve:evaluate(t/d) + b end
end

The usage with tween.lua is simple:

local label = { x=200, y=0, text = "hello" }
local labelTween = tween.new(4, label, {y=300}, cubicbezier(.35, .97, .58, .61))

I know and understand that tween.lua is not a LÖVE library but a Lua library in general, but it will be nice if this possibility would be at least documented somewhere (since it is pretty simple and nice)

PS: If you dont know what those freaking numbers are (as I was also confused at first), check this

tweens table makes Tween act like a singleton.

I don't know if it is intentional, but if you require tween into 2 separate local variables and do an update(dt) on one of them, both get updated.
Using one table as the metatable creates a sort of self-contained singleton hybrid.

inExpo cannot end on 'c' value

I used to insert if t == d then return b + c end to solve it for my project, like following:

local function inExpo(t, b, c, d) if t == 0 then return b end if t == d then return b + c end return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001 end

But now I am really curious to know why - c * 0.001 shown in this function.

It is more like a question about why this implementation does not following others

Stack Traceback when running the example

Here is what I get when trying to run the give example in terminal with command "lua a.lua",

lua: /usr/local/lib/lua/5.4/tween.lua:344: dt must be a number
stack traceback:
	[C]: in function 'assert'
	/usr/local/lib/lua/5.4/tween.lua:344: in method 'update'
	...skaran/Documents/Development/LUA/a.lua:7: in main chunk
	[C]: in ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.