diff --git a/flare_dart/lib/math/aabb.dart b/flare_dart/lib/math/aabb.dart index f0212f4..3f359ff 100644 --- a/flare_dart/lib/math/aabb.dart +++ b/flare_dart/lib/math/aabb.dart @@ -81,6 +81,11 @@ class AABB { return a[0] <= b[0] && a[1] <= b[1] && b[2] <= a[2] && b[3] <= a[3]; } + static bool pointInside(AABB a, Vec2D point) { + return a[0] <= point[0] && a[2] >= point[0] + && a[1] <= point[1] && a[3] >= point[1]; + } + static bool isValid(AABB a) { double dx = a[2] - a[0]; double dy = a[3] - a[1]; diff --git a/flare_flutter/lib/flare.dart b/flare_flutter/lib/flare.dart index 7e430b8..2daa0f2 100644 --- a/flare_flutter/lib/flare.dart +++ b/flare_flutter/lib/flare.dart @@ -67,6 +67,7 @@ abstract class FlutterActorDrawable { void onAntialiasChanged(bool useAA); void onBlendModeChanged(ui.BlendMode blendMode); + List hitTest(ui.Offset point) => []; void draw(ui.Canvas canvas); List> get clipShapes; @@ -292,6 +293,14 @@ class FlutterActorShape extends ActorShape with FlutterActorDrawable { return path; } + @override + List hitTest(ui.Offset point) { + if (path.contains(point) && (fills != null)) { + return [name]; + } + return []; + } + @override void draw(ui.Canvas canvas) { if (!doesDraw) { @@ -862,6 +871,22 @@ class FlutterActorArtboard extends ActorArtboard { } } + List deepHitTest(ui.Offset point) { + List nodeNameList = []; + if (drawableNodes != null) { + for (final ActorDrawable drawable in drawableNodes) { + if (drawable is FlutterActorDrawable) { + List nodeNames = + (drawable as FlutterActorDrawable).hitTest(point); + if (nodeNames.isNotEmpty) { + nodeNameList.addAll(nodeNames); + } + } + } + } + return nodeNameList; + } + void draw(ui.Canvas canvas) { if (clipContents) { canvas.save(); diff --git a/flare_flutter/lib/flare_controls.dart b/flare_flutter/lib/flare_controls.dart index ed89a16..aacf44f 100644 --- a/flare_flutter/lib/flare_controls.dart +++ b/flare_flutter/lib/flare_controls.dart @@ -1,8 +1,10 @@ import 'dart:math'; import 'package:flare_dart/math/mat2d.dart'; +import 'package:flare_dart/math/vec2d.dart'; import 'flare.dart'; import 'flare_actor.dart'; import 'flare_controller.dart'; +import 'dart:ui'; /// [FlareControls] is a concrete implementation of the [FlareController]. /// @@ -15,6 +17,7 @@ class FlareControls extends FlareController { /// The current [ActorAnimation]. String _animationName; + List _toBeRemoved = []; final double _mixSeconds = 0.1; /// The [FlareAnimationLayer]s currently active. @@ -47,8 +50,23 @@ class FlareControls extends FlareController { } } + void stop(String name) { + _toBeRemoved.add(name); + } + + // Storage for our matrix to get global Flutter coordinates into Flare world coordinates. + Mat2D globalToFlareWorld = Mat2D(); + List deepHitTest(Offset point) { + Vec2D pointGlobal = Vec2D.fromValues(point.dx, point.dy); + Vec2D pointFlare = Vec2D(); + Vec2D.transformMat2D(pointFlare, pointGlobal, globalToFlareWorld); + return _artboard.deepHitTest(Offset(pointFlare[0], pointFlare[1])); + } + @override - void setViewTransform(Mat2D viewTransform) {} + void setViewTransform(Mat2D viewTransform) { + Mat2D.invert(globalToFlareWorld, viewTransform); + } /// Advance all the [FlareAnimationLayer]s that are currently controlled /// by this object, and mixes them accordingly. @@ -59,6 +77,13 @@ class FlareControls extends FlareController { bool advance(FlutterActorArtboard artboard, double elapsed) { /// List of completed animations during this frame. List completed = []; + //remove all stopped animations + for (final String animationName in _toBeRemoved) { + _animationLayers.removeWhere((animation) => + animation.name == animationName); + onCompleted(animationName); + } + _toBeRemoved.clear(); /// 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