A Unity3D plugin that makes it incredibly easy animate almost anything using fluent functions. Fluent Animation takes a procedural/functional way of solving the decade old animation queue and callback hell problem.
- Move, rotate, scale almost anything
- Execute animations in parallel
- Comes with 31 easing effects
- Support for custom easing effect
- Animate objects on a set of way points
- Animate custom components
- Animate custom fields/properties
- Extend class to add more features
- Customize animation update type
- Loop, control, or jump to specific animation
- Bezier, Spline and Linear waypoint paths
- Comes with 5 free easy to learn demos
Import the Fluent Animation package into your project and explore the directories.
Try out the given demos inside the FluentAnimation\Demo\Scene
folder. In each of the demos, there is a scene, and a custom script with the same name attached to the MainCamera
. Open that script to see how the demo works.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0), 3f)
.RotateTo(Quaternion.Euler(0, 90, 30), 3f);
So what happened here? Well, the New()
method created a new animation component and attached it to a dummy game object. The With
method made sure that all next animations are applied to the given gameObject
. The MoveTo
and RotateTo
functions animated the position and rotation of the gameObject
in series in 3 seconds.
The animations were queued. The rotation occured after the movement, and that's the beauty of procedural/fluent scripting.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0), 2f)
.Parallel(
Fluent.Animation.New().MoveTo(new Vector3(100, 0, 100)),
Fluent.Animation.New().RotateTo(Quaternion.Euler(0, 90, 0))
)
.MoveTo(new Vector3(0,0,0), 1f);
So what happened now? Well...
- The first
MoveTo
moved the object - After that, the
Parallel
function started off 2 parallel animations (MoveTo
andRotateTo
) - And then, the
MoveTo
took the object back to 0,0,0
This shows how animations can be triggered in either series, parallel, or a combination of both.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0), 3f, Fluent.Animation.LookType.Interpolate, Fluent.Easing.Circular.Out);
You can make use of over 30 easing functions to make your animations feel more natural. The easing list is given in the references section. The LookType
tells how the object rotates during movement.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0), 3f)
.Then(() => {
// do something
})
.RotateBy(Quaternion.Euler(0,90,45))
.Then(() => {
// do something again
});
Then
can be used to trigger custom functions.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0))
.RotateBy(Quaternion.Euler(0, 90, 90))
.Loop();
When the rotation has ended, the Loop
statement restarts the whole animation queue. If you want to go back to a specific animation step, you can use Label
and Goto
statements.
Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0))
.Label("Good Game")
.RotateBy(Quaternion.Euler(0, 90, 90))
.Goto("Good Game");
The Label
function puts a point in a queue. The Goto
statement goes back to the point defined by the label (in this case "Good Game"
). You can also use Goto
statement to goto a certain step (in past or future) if a condition is met, using GotoIf
.
Fluent gives the ability to animate almost anything we like. Let's try animating a customProperty
of a CustomComponent
.
Fluent.Animation.New()
.AnimateProperty(gameObject.GetComponent<CustomComponent>(), 'customProperty', 20f, 30f, 2f)
This will animate the customProperty
from 20f to 30f in 2 seconds. This code also works on built-in components and properties. AnimatePropertyBy
can be used if you don't want to specify the starting value.
Open the PathDemo
to see how an object can follow a given path. Here's how you can use paths for animating your own objects.
- Create an empty GameObject and add
Fluent.Path
component to it. - Add several empty game objects with
Fluent.PathPoint
component, within that gameObject. - Drag the child gameObjects around and you would observe a path between those points.
- Change the
PathInterpolation
property of the parentPath
component to your needs. - Use the following script in a new component:
Fluent.Animation.New ()
.With (gameObject)
.MoveOnPath (pathObject.GetComponent<Fluent.Path>(), Fluent.Animation.LookType.Forward, 3f)
This is going to move a specific object on a path, looking forward, within 3 seconds. If you want to keep it moving forever, you can add Loop()
at the end of the animation queue, and set the ConnectedTerminals
property of Path
to true.
If you change position or rotation of any PathPoint
after the during the game, make sure you call the Bake()
function of Path
.
You can make use of certain events to make your animation queue even more powerful.
var animation = Fluent.Animation.New()
.With(gameObject)
.MoveTo(new Vector3(0, 100, 0), 3f);
animation.AnimationEnded += animationEnded;
private void animationEnded(Fluent.Animation animation) {
// called when the animation queue has ended
}
Check out the reference for the events list.
New*()*
Creates a new Fluent.Animation component and attaches it to a dummy GameObject.
New*(GameObject)*
Creates a new Fluent.Animation component and attaches it to the specified GameObject.
ClearAll*()*
Removes all Fluent.Animation components from the dummy GameObject.
ClearAll*(GameObject)*
Removes all Fluent.Animation components from the specific GameObject.
These methods can be used in a chain form. And are triggered when the previous animation steps are completed.
Then*(Action)*
Performs an action.
WaitFor*(float seconds)*
Waits for given # of seconds.
WaitUntil*(TaskCondition)*
Waits until a delegate/func returns true.
Parallel*(... Fluent.Animation)*
Executes given animations in parallel.
Loop*()*
Restarts the animation queue.
LoopIf*(TaskCondition)*
Restarts the animation queue if the condition is met.
With*(GameObject)*
Runs all subsequent animations in the given GameObject.
MoveTo*(Vector3 destination, float duration = 1f, LookType lookRotation = LookType.Interpolate, Func<float, float> easing = null)*
Moves the selected gameObject to a destination.
MoveBy*(Vector3 offset, float duration = 1f, LookType lookRotation = LookType.Interpolate, Func<float, float> easing = null)*
Moves the selected gameObject by offset.
MoveBy*(float distance, Quaternion angle, float duration = 1f, LookType lookRotation = LookType.Interpolate, Func<float, float> easing = null)*
Moves the selected gameObject using angle/direction and distance.
Move<Direction>(float distance, float duration = 1f, LookType lookRotation = LookType.Interpolate, Func<float, float> easing = null)
Makes the object move forward, backward, up, down, left, or right relative to world rotation.
MoveRelatively<Direction>(float distance, float duration = 1f, LookType lookRotation = LookType.Interpolate, Func<float, float> easing = null)
Makes the object move forward, backward, up, down, left, or right relative to it's own rotation.
RotateTo*(Quaternion expectedRotation, float duration = 1f, Func<float, float> easing = null)*
Rotates to the given rotation.
RotateBy*(Quaternion deltaRotation, float duration = 1f, Func<float, float> easing = null)*
Rotates by the given rotation offset.
LookTo*(Vector3 pointOfInterest, float duration = 1f, Func<float, float> easing = null)*
Looks to a given point of interest.
ScaleTo*(Vector3 expectedScale, float duration = 1f, Func<float, float> easing = null)*
Scales the object to the given scale.
ScaleBy*(Vector3 deltaScale, float duration = 1f, Func<float, float> easing = null)*
Scales the object by the given scale offset.
AnimateProperty*(object host, string propertyName, object startValue, object endValue, float duration, Func<float, float> easing = null)*
Animates a custom property of a host, from startValue, to endValue, in fiven duration using given easing function.
AnimateProperty*(object host, string propertyName, object endValue, float duration, Func<float, float> easing = null)*
Animates a custom property of a host, given the endValue only.
AnimatePropertyBy*(object host, string propertyName, object offset, float duration = 1f, Func<float, float> easing = null)*
Animates a custom property by an
offset
.
AnimateValue*(T startValue, T endValue, Action<T, float> callback, float duration = 1f, Func<float, float> easing = null)*
Animates a new value from
startValue
toendValue
. Thecallback
is triggered on each step and is used to make use of the value being animated.
MoveOnPath*(Path path, LookType lookRotation = LookType.Forward, float speedMultiplier = 1f, Func<float, float> easing = null)*
Moves a GameObject on the given path.
RotateOnPath*(Path path, float speedMultiplier = 1f, Func<float, float> easing = null)*
Rotates the given GameObject according to the rotation of PathPoints in the given path.
ChangeUpdateType*(UpdateType)*
Changes the update type for all following animations. Useful for animating cameras, physics, and custom dynamics.
Log*(string message)*
Logs a message to the console when the step occurs.
Label*(string label)*
Places a label in that point of animation queue.
Goto*(string label)*
Goes to a specific point in queue defined by the label.
GotoIf*(string label, TaskCondition)*
Goes to a certain point if a condition has been met.
These methods are used to control the state of the animation queue, or extend the Fluent.Animation with new functionality. They should not be used in a chained way.
Suspend*()*
Temporarily pauses the animation, and all sub/parallel animations.
Resume*()*
Resumes a suspended animation queue.
Restart*()*
Restarts the animation queue.
GotoIndex*(int index)*
Goes to a specific index in a queue.
Dequeue*()*
Removes the animation step from front of the queue.
Enqueue*(Step step)*
Adds a new animation step to the queue.
NewStep*() : Step*
Creates a new animation step.
Refer to the event handling example above to see how to use these.
AnimationEnded*(Animation)*
Triggers when the animation queue has ended has ended.
AnimationStopped*(Animation)*
Triggers when the animation queue has ended has been stopped.
AnimationSuspended*(Animation)*
Triggers when the animation queue has been paused/suspended.
AnimationResumed*(Animation)*
Triggers when a suspended animation queue has been resumed.
PathPointEnter*(GameObject gameObject, PathPoint pathPoint)*
Triggered when a
PathPoint
is entered by a gameObject duringMoveOnPath
animation.
PathPointMove*(GameObject gameObject, PathPoint pathPoint, float progress)*
Triggered when a gameObject is moving on
PathPoint
duringMoveOnPath
animation.
Check out the easing example above to see how to use each easing function, and refer to Easings.net to see how each function feels like.
- Linear
- Quadratic.In
- Quadratic.Out
- Quadratic.InOut
- Cubic.In
- Cubic.Out
- Cubic.InOut
- Quartic.In
- Quartic.Out
- Quartic.InOut
- Quintic.In
- Quintic.Out
- Quintic.InOut
- Sinusoidal.In
- Sinusoidal.Out
- Sinusoidal.InOut
- Exponential.In
- Exponential.Out
- Exponential.InOut
- Circular.In
- Circular.Out
- Circular.InOut
- Elastic.In
- Elastic.Out
- Elastic.InOut
- Back.In
- Back.Out
- Back.InOut
- Bounce.In
- Bounce.Out
- Bounce.InOut
Bake*()*
Bakes a path according to each point. Should be called as soon as any
PathPoint
is changed.
ConnectedTerminals*: bool*
Joins the start and end points of this path. Used to loop animations.
PathInterpolation*: enum*
Tells how the object would move on this path. It can be:
- Linear (in a straight point to point way)
- Bezier (in a curved fashion, object may not pass through every point)
- Spline (same as Bezier, but object would definititely pass through every point)
OnEnter*(PathPoint)*
Triggered when this PathPoint is entered by any object.
OnMove*(PathPoint, float progress)*
Triggered when a gameObject is moving on this PathPoint.
progress
can be from 0 to 1.
Duration*: float*
Time it takes to reach this
PathPoint
in seconds.
Key*: string*
Used to store additional info on this point.
Please let me know if you have any additional questions :)