-
Notifications
You must be signed in to change notification settings - Fork 0
07 Tweens
For a quick demo, check out the tweens example game.
A tween is a description of a desired change over a period of time.
Currently tweens are limited to sprites, they allow you to modify an attribute of the sprite by specifying a target value (relative to the current value), how quickly the target value should be reached, and with what kind of progression curve (linear, quadratic, elastic etc. see Easing Functions). Configuration options are available for reversing and repeating tweens, as well at triggering code at different points as the tween progresses.
The quip.tweens/tween
function requires a keyword (the field to modify) and a scalar value (the target). It returns a tween that can be attached to a sprite with the quip.tween/add-tween
function.
;; A simple tween which will rotate a sprite from its current `:rotation` 180 degrees.
(def t (quip.tween/tween :rotation 180))
;; Adding the tween to the player sprite will start the tween
(quip.tween/add-tween player t)
⚠️ You must call thequip.tween/update-sprite-tweens
function on the game state in your scene's update function:
(defn update-level-01
[state]
(-> state
quip.sprite/update-scene-sprites
;; You must update tweens for them to work
quip.tween/update-sprite-tweens))
You can set the number of frames that a tween should take to complete by specifying the :step-count
. This defaults to 100, lower numbers will make the tween complete faster, but very low numbers won't be as smooth.
;; This tween will flip the sprite in 15 frames instead of 100
(def t (quip.tween/tween
:rotation
180
:step-count 15))
If the field you want to tween is not a scalar, numerical value (such as :pos
or :vel
which are vectors) you must supply an :update-fn
function.
This function should take the current value of the field, and a delta d
to modify it by, it should return the new value of the field.
;; We want to tween the x value of `:pos`
(def t (quip.tween/tween
:pos
30
:update-fn (fn [[x y] d]
[(+ x d) y])))
For convenience, the quip.tween
namespace provides the tween-x-fn
and tween-y-fn
functions which will tween the first and second elements of a vector respectively.
;; It's often easier to use the built in function
(def t (quip.tween/tween
:pos
30
:update-fn quip.tween/tween-x-fn))
By default a tween will use a linear easing function, meaning the rate of change to the value will be constant. You can specify other easing functions with the :easing-fn
optional argument.
You can define you own easing function as a function of a single number x
(between 0 and 1) which represents the progress of the tween. Your function should return a value between 0 and 1 which represents how much of the change to the value should have happened.
;; This easing function describes a quadratic curve from 0 to 1
(defn example-ease
[x]
(* x x))
It's rare that you need to define your own easing function. The quip.tween
namespace makes several easing functions available for convenience. Representations of these functions can be seen at easings.net.
ease-sigmoid
ease-in-sine
ease-out-sine
ease-in-out-sine
ease-in-quad
ease-out-quad
ease-in-out-quad
ease-in-cubic
ease-out-cubic
ease-in-out-cubic
ease-in-quart
ease-out-quart
ease-in-out-quart
ease-in-quint
ease-out-quint
ease-in-out-quint
ease-in-expo
ease-out-expo
ease-in-out-expo
ease-in-circ
ease-out-circ
ease-in-out-circ
ease-in-back
ease-out-back
ease-in-out-back
ease-in-elastic
ease-out-elastic
ease-in-out-elastic
ease-in-bounce
ease-out-bounce
ease-in-out-bounce
You can make a tween "yoyo" by setting the :yoyo?
optional argument to true
. This will make the tween reverse itself once it has gotten to the target value. If your tween is modifying a non-scalar field, you must also provide a :yoyo-update-fn
which should do the opposite of your :update-fn
, i.e. reduce the current value by the delta instead of increase it.
;; We want to tween the x value of `:pos` and yoyo back to the original value
(def t (quip.tween/tween
:pos
30
:update-fn (fn [[x y] d]
[(+ x d) y])
:yoyo? true
:yoyo-update-fn (fn [[x y] d]
[(- x d) y])))
Once again, the quip.tween
namespace provides built-in functions for yoyo updates on [x y]
vectors, tween-x-yoyo-fn
and tween-y-yoyo-fn
.
;; It's often easier to use the built in functions
(def t (quip.tween/tween
:pos
30
:update-fn quip.tween/tween-x-fn
:yoyo? true
:yoyo-update-fn quip.tween/tween-x-yoyo-fn))
You can also specify a function to modify the sprite when it has completed the initial tween and is about to start the yoyo. The :on-yoyo-fn
optional argument should be a function that takes the current value of the sprite and returns the updated sprite.
(def t (quip.tween/tween
:pos
30
:update-fn quip.tween/tween-x-fn
:yoyo? true
:yoyo-update-fn quip.tween/tween-x-yoyo-fn
:on-yoyo-fn (fn [s]
;; Turn the sprite around before returning
(flip-direction s))))
You can specify a number of times to repeat the tween (including yoyo) with the :repeat-times
optional argument. The value should be a positive integer, if you want a tween to repeat indefinitely you can simply use the ##Inf
symbolic value for infinity.
;; Flip the sprite upside down, then back up, 10 times
(def t (quip.tween/tween
:rotation
180
:yoyo? true
:repeat-times 10))
You can also specify a function to modify the sprite when a repeat has completed with the :on-repeat-fn
optional argument.
;; Flip the sprite upside down, then back up, forever
(def t (quip.tween/tween
:rotation
180
:yoyo? true
:repeat-times ##Inf
:on-repeat-fn (fn [s]
(prn "I don't feel well")
s)))
Finally you can specify a function to modify the sprite when a tween has fully completed (including all yoyos and repetitions) with the :on-complete-fn
optional argument.
⚠️ the:on-complete-fn
function will never be called if:repeat-times
id##Inf
.
;; Flip the sprite upside down, then back up, gain some xp for doing so
(def t (quip.tween/tween
:rotation
180
:yoyo? true
:on-complete-fn (fn [s]
(add-xp s 200))))