Skip to content
66 changes: 43 additions & 23 deletions flare_flutter/lib/flare_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import 'flare.dart';
import 'flare_actor.dart';
import 'flare_controller.dart';

/// [TimedAnimation] holds a reference to [FlareAnimationLayer]s
/// and [currentTime] maintains that layers current animation timeline
/// for mixing purposes
class TimedAnimation {
FlareAnimationLayer layer;
double currentTime; // how many seconds have elapsed
}

/// [FlareControls] is a concrete implementation of the [FlareController].
///
/// This controller will provide some basic functionality, such as
Expand All @@ -15,10 +23,13 @@ class FlareControls extends FlareController {

/// The current [ActorAnimation].
String _animationName;
final double _mixSeconds = 0.1;

/// The [FlareAnimationLayer]s currently active.
final List<FlareAnimationLayer> _animationLayers = [];
/// The [TimedAnimation]s currently active.
final List<TimedAnimation> _animations = [];

/// Used as a reference for each animation layer
/// to stay in sync
double _ticker = 0.0;

/// Called at initialization time, it stores the reference
/// to the current [FlutterActorArtboard].
Expand All @@ -34,15 +45,23 @@ class FlareControls extends FlareController {
/// to the end of the list of currently playing animation layers.
void play(String name, {double mix = 1.0, double mixSeconds = 0.2}) {
_animationName = name;

if (_animationName != null && _artboard != null) {
int layerIndex = _animations.indexWhere((ani) => ani.layer.name == name);
ActorAnimation animation = _artboard.getAnimation(_animationName);
if (animation != null) {
_animationLayers.add(FlareAnimationLayer()

if (animation != null && layerIndex == -1) {
_animations.add(TimedAnimation()
..layer = (FlareAnimationLayer()
..name = _animationName
..animation = animation
..mix = mix
..mixSeconds = mixSeconds);
..mixSeconds = mixSeconds)
..currentTime = mix * mixSeconds);
isActive.value = true;
} else if (layerIndex >= 0) {
/// If we already have reference to this, update the seconds
_animations[layerIndex].layer.mixSeconds = mixSeconds;
}
}
}
Expand All @@ -58,39 +77,40 @@ class FlareControls extends FlareController {
@override
bool advance(FlutterActorArtboard artboard, double elapsed) {
/// List of completed animations during this frame.
List<FlareAnimationLayer> completed = [];
List<TimedAnimation> completed = [];

_ticker += elapsed;

/// This loop will mix all the currently active animation layers so that,
/// if an animation is played on top of the current one, it'll smoothly mix
/// between the two instead of immediately switching to the new one.
for (int i = 0; i < _animationLayers.length; i++) {
FlareAnimationLayer layer = _animationLayers[i];
layer.mix += elapsed;
layer.time += elapsed;
/// between the two instead of immediately switching to the new one.
for (int i = 0; i < _animations.length; i++) {
FlareAnimationLayer layer = _animations[i].layer;
layer.time = _ticker;
_animations[i].currentTime += layer.name == _animationName ? elapsed : -elapsed;
_animations[i].currentTime = max(0.0, min(layer.mixSeconds, _animations[i].currentTime));

double mix = (_mixSeconds == null || _mixSeconds == 0.0)
? 1.0
: min(1.0, layer.mix / _mixSeconds);
layer.mix = max(0.0, min(1.0, _animations[i].currentTime / layer.mixSeconds));

/// Loop the time if needed.
if (layer.animation.isLooping) {
layer.time %= layer.animation.duration;
}

/// Apply the animation with the current mix.
layer.animation.apply(layer.time, _artboard, mix);
layer.animation.apply(layer.time, _artboard, layer.mix);

/// Add (non-looping) finished animations to the list.
if (layer.time > layer.animation.duration) {
completed.add(layer);
/// Axe it after it's finished mixing
if (layer.mix == 0) {
completed.add(_animations[i]);
}
}

/// Notify of the completed animations.
for (final FlareAnimationLayer animation in completed) {
_animationLayers.remove(animation);
onCompleted(animation.name);
for (final TimedAnimation animation in completed) {
_animations.remove(animation);
onCompleted(animation.layer.name);
}
return _animationLayers.isNotEmpty;
return _animations.isNotEmpty;
}
}
3 changes: 1 addition & 2 deletions flare_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flare_dart:
path: ../flare_dart/
flare_dart: ^2.3.4
meta: ^1.0.5
dev_dependencies:
flutter_test:
Expand Down