ActorAnimation

Accessing Properties of Animations

ActorAnimation & Properties

implements ActorAnimation Class

The ActorAnimation is the class that handles a specific animation of a Rive Actor. You can access different properties of the specified animation to customize your Actor at runtime.

Duration allows you to obtain how long the animation will last, which is returned as a double:

getAnimation("name_of_Animation").duration

Looping is returned as a boolean to check whether an animation loops:

getAnimation("name_of_Animation").isLooping

FPS allows you to check an animation's frames per second, which is returned as an integer:

getAnimation("name_of_Animation").fps

Controller

The Rive Controller is a general-purpose interface for customizing the behavior of an animation at runtime. By extending the Controller class you can override functions to have more control of the Rive Actor. This allows you access to things like being notified when an animation is complete, advancing through different states of an animation, etc. There are three main methods used when setting up a custom controller: initialize, advance and setViewTransform.

Initialize

The initialize method is called once when the controller is first created. Use it to fetch references to animation components that will be affected by the controller:

initialize(artboard)

Set View Transform

The setViewTransform method relays the information regarding the global viewTransform matrix of the Actor that this controller is attached to. This is also called every frame, and relays information regarding the current view matrix of the animation.

setViewTransform(Mat2D viewTransform)

Advance

The advance method will advance the animation of the current 'artboard' by elapsed. It is called every frame. Every time the artboard advances, it relays the elapsed time to the controller, which can thus perform custom actions. This method's elapsed parameter passes the time passed since the last frame. This must return a boolean.

bool advance(artboard, elapsed)

Time and Mixing

Animation Time

The current time of an animation can be manipulated at runtime inside of a custom controller. For example, in the advance method you can achieve different effects (like animating a character to aim its weapon based on a mouse pointer) by dividing the entire length of the animation by another parameter such as elapsed time.

Flutter Sample
Swift Sample
React Sample
JS Sample
C++ Sample
Flutter Sample
import 'package:flare_flutter/flare_actor.dart';
import 'package:flare_flutter/flare_controller.dart';
import 'package:flare_flutter/flare.dart';
...
ActorAnimation _myAnimation;
//modify this to change the fill
double _animTime = 0.00;
double _currentAnimTime = 0;
void initialize(FlutterActorArtboard artboard) {
_myAnimation= artboard.getAnimation("animationString");
}
bool advance(FlutterActorArtboard artboard, double elapsed) {
_currentAnimTime +=
(_animTime - _currentAnimTime) * min(1, elapsed * 5);
_myAnimation.apply(
_currentAnimTime * _myAnimation.duration, artboard, 1);
}
...
Swift Sample
open class CustomController: FlareSkViewController {
open func onCompleted(name: String) {
if(name == "AnimationName"){
//Do Something
}
}
override open func advanceControls(by elapsed: Double) -> Bool {
guard
let fView = view as? FlareSkView,
let artboard = fView.artboard
else { return false }
return true;
}
override open func setViewTransform(viewTransform: Mat2D) {}
..
}
React Sample
constructor()
{
super();
this._ActorAnimator = null;
this._CanPlay = false;
this._AnimTime = 0;
}
initialize(artboard)
{
this._ActorAnimator = this._Artboard.getAnimation("animationString");
}
advance(artboard, elapsed)
{
this._AnimTime += elapsed *1;
if (this._CanPlay === true)
{
this._ActorAnimator.apply(this._AnimTime % this._ActorAnimator.duration, artboard, 1);
}
}
JS Sample
function FlareExample(canvas, ready)
{
this._Graphics = new Flare.Graphics(canvas);
this._Graphics.initialize("../build/", () =>
{
this._LastAdvanceTime = Date.now();
this._ViewTransform = mat2d.create();
this._AnimationInstance= null;
const _This = this;
_ScheduleAdvance(_This);
_Advance(_This);
ready();
});
}
function _Advance(_This)
{
_This.setSize(window.innerWidth, window.innerHeight);
const now = Date.now();
const elapsed = (now - _This._LastAdvanceTime)/1000.0;
_This._LastAdvanceTime = now;
const actor = _This._ActorInstance;
if (_This._AnimationInstance)
{
const ai = _This._AnimationInstance;
ai.time = ai.time + elapsed;
ai.apply(_This._ActorInstance, 1.0);
}
if(actor)
{
const graphics = _This._Graphics;
const w = graphics.viewportWidth;
const h = graphics.viewportHeight;
const vt = _This._ViewTransform;
vt[0] = _Scale;
vt[3] = _Scale;
vt[4] = (-_ViewCenter[0] * _Scale + w/2);
vt[5] = (-_ViewCenter[1] * _Scale + h/2);
/** Advance the actor to its new time. */
actor.advance(elapsed);
}
_Draw(_This, _This._Graphics);
/** Schedule a new frame. */
_ScheduleAdvance(_This);
}
C++ Sample
...
flare::ActorAnimation* animation = artboard->animation(animationName);
...
float animationTime = 0.0f;
double time = glfwGetTime();
float elapsed = (float)(time - lastTime);
lastTime = time;
if (animation != nullptr)
{
animationTime += elapsed;
animation->apply(std::fmod(animationTime, animation->duration()), artboard, 1.0);
}
artboard->advance(elapsed);
...

Animation Mixing

This is a blending parameter to allow smoothing between concurrent animations. By setting the mix to 1, the current animation will fully replace the existing values. By ramping up mix with values between 0 and 1, the transition from one animation to the next will be more gradual as it gets mixed in, preventing popping effects.

Flutter Sample
Swift Sample
React Sample
JS Sample
C++ Sample
Flutter Sample
import 'package:flare_flutter/flare_controls.dart';
...
final FlareControls _flareControls = FlareControls();
...
{
_flareControls.play("animationString", mix: 0.5, mixSeconds: 1.0);
}
Swift Sample
self.flareController!.play(name: "AnimationName", mix: 0.5, mixSeconds: 1.0)
React Sample
import FlareComponent from 'flare-react';
initialize(artboard)
{
this._ActorAnimator = artboard.getAnimation("animation_String");
}
advance(artboard, elapsed)
{
this._AnimTime += elapsed *1;
this._ActorAnimator.apply(this._AnimTime % this._ActorAnimator.duration, artboard, 1);
}
JS Sample
function FlareExample(canvas, ready)
{
this._Graphics = new Flare.Graphics(canvas);
this._Graphics.initialize("../build/", () =>
{
this._LastAdvanceTime = Date.now();
this._ViewTransform = mat2d.create();
this._AnimationInstance= null;
const _This = this;
_ScheduleAdvance(_This);
_Advance(_This);
ready();
});
}
function _Advance(_This)
{
_This.setSize(window.innerWidth, window.innerHeight);
const now = Date.now();
const elapsed = (now - _This._LastAdvanceTime)/1000.0;
_This._LastAdvanceTime = now;
const actor = _This._ActorInstance;
if (_This._AnimationInstance)
{
const ai = _This._AnimationInstance;
//Apply Mix Time here
ai.time = ai.time + elapsed;
ai.apply(_This._ActorInstance, 1.0);
}
if(actor)
{
const graphics = _This._Graphics;
const w = graphics.viewportWidth;
const h = graphics.viewportHeight;
const vt = _This._ViewTransform;
vt[0] = _Scale;
vt[3] = _Scale;
vt[4] = (-_ViewCenter[0] * _Scale + w/2);
vt[5] = (-_ViewCenter[1] * _Scale + h/2);
/** Advance the actor to its new time. */
actor.advance(elapsed);
}
_Draw(_This, _This._Graphics);
/** Schedule a new frame. */
_ScheduleAdvance(_This);
}
C++ Sample
coming soon

FlareControls

By defining a Rive controller in the Flutter and Swift runtimes, you can use the play("animationString") method to give you more control over which animation is currently playing with out the need to create a custom controller class.

Flutter Sample
Swift Sample
C++ Sample
Flutter Sample
import 'package:flare_flutter/flare_controls.dart';
...
final FlareControls _flareControls = FlareControls();
...
{
...child: FlareActor("assets/FlareFile.flr",
controller: _flareControls
),
...
}
...
{
_flareControls.play("myAnimationName");
}
Swift Sample
private var flareController: FlareSkControls? = nil
...
override func viewDidLoad() {
super.viewDidLoad()
flareController = FlareSkControls(for: "FlareTest.flr", CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
flareController!.animationName = "Animation1"
addChild(flareController!)
}
...
self.flareController!.play(name: "Animation2", mix: 0.5, mixSeconds: 1.0)
...
C++ Sample
...
flare::SkrActorArtboard* artboard = actor->artboard<flare::SkrActorArtboard>();
artboard->initializeGraphics();
flare::ActorAnimation* animation = artboard->animation("animationString");
...