From f473869a23304ae2fee1dac3056e8bd2c00450fc Mon Sep 17 00:00:00 2001 From: Luan Nico Date: Tue, 11 Aug 2026 01:37:59 -0400 Subject: [PATCH 1/2] chore!: Kill legacy Vertical/Horizontal drag detectors --- doc/flame/inputs/gesture_input.md | 14 -- doc/flame/migration.md | 33 +++ packages/flame/lib/events.dart | 8 +- packages/flame/lib/src/game/flame_game.dart | 4 +- .../game_widget/gesture_detector_builder.dart | 24 --- .../flame/lib/src/gestures/detectors.dart | 48 ----- .../game_widget/game_widget_drag_test.dart | 62 ------ .../flame/test/gestures/detectors_test.dart | 189 ------------------ 8 files changed, 35 insertions(+), 347 deletions(-) diff --git a/doc/flame/inputs/gesture_input.md b/doc/flame/inputs/gesture_input.md index e6dec94019d..a74bdcb5cbf 100644 --- a/doc/flame/inputs/gesture_input.md +++ b/doc/flame/inputs/gesture_input.md @@ -24,20 +24,6 @@ Detectors will be deprecated in the future. Prefer `Callbacks` instead. ``` ```text -- VerticalDragDetector - - onVerticalDragDown - - onVerticalDragStart - - onVerticalDragUpdate - - onVerticalDragEnd - - onVerticalDragCancel - -- HorizontalDragDetector - - onHorizontalDragDown - - onHorizontalDragStart - - onHorizontalDragUpdate - - onHorizontalDragEnd - - onHorizontalDragCancel - - PanDetector - onPanDown - onPanStart diff --git a/doc/flame/migration.md b/doc/flame/migration.md index 63ab8716442..4949be29451 100644 --- a/doc/flame/migration.md +++ b/doc/flame/migration.md @@ -7,6 +7,39 @@ major versions of Flame, together with the steps required to migrate your code. ## Migrating from v1.38.0 to v2.0.0 +### `VerticalDragDetector` and `HorizontalDragDetector` removed + +Both game-level mixins have been removed, with no direct replacement in Flame. + +They existed only to expose Flutter's `VerticalDragGestureRecognizer` and +`HorizontalDragGestureRecognizer`, whose distinguishing feature is not the filtering itself but how +they behave in Flutter's gesture arena: an axis-constrained recognizer yields to a competitor on the +other axis. That matters when a `GameWidget` is nested inside a scrollable, which is a concern of +the widget tree rather than of the game, and it is not something the component-level `DragCallbacks` +can reproduce. + +If your game accepts drags on any axis, use `DragCallbacks`, which can be mixed directly into your +game class: + +```dart +// Before +class MyGame extends FlameGame with VerticalDragDetector { + @override + void onVerticalDragUpdate(DragUpdateInfo info) { /* ... */ } +} + +// After +class MyGame extends FlameGame with DragCallbacks { + @override + void onDragUpdate(DragUpdateEvent event) { /* ... */ } +} +``` + +If you specifically need the arena behaviour, wrap your `GameWidget` in Flutter's own +[`GestureDetector`](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html) and use its +`onVerticalDragUpdate` / `onHorizontalDragUpdate` callbacks. + + ### `ForcePressDetector` removed The `ForcePressDetector` mixin and its `ForcePressInfo` event class have been removed, with no diff --git a/packages/flame/lib/events.dart b/packages/flame/lib/events.dart index 28bd1ff2ca2..7062c09c4e2 100644 --- a/packages/flame/lib/events.dart +++ b/packages/flame/lib/events.dart @@ -79,13 +79,7 @@ export 'src/events/multi_drag_scale_recognizer.dart' export 'src/game/mixins/keyboard.dart' show HasKeyboardHandlerComponents, KeyboardEvents; export 'src/gestures/detectors.dart' - show - HorizontalDragDetector, - MouseMovementDetector, - PanDetector, - ScaleDetector, - ScrollDetector, - VerticalDragDetector; + show MouseMovementDetector, PanDetector, ScaleDetector, ScrollDetector; export 'src/gestures/events.dart' show DragDownInfo, diff --git a/packages/flame/lib/src/game/flame_game.dart b/packages/flame/lib/src/game/flame_game.dart index 8796ab9d542..c0e035e0d0d 100644 --- a/packages/flame/lib/src/game/flame_game.dart +++ b/packages/flame/lib/src/game/flame_game.dart @@ -247,9 +247,7 @@ class FlameGame extends ComponentTreeRoot bool containsEventHandlerAt(Vector2 position) { // Game-level detector mixins handle events for the entire game surface, // so any in-bounds point is a hit. - if (this is VerticalDragDetector || - this is HorizontalDragDetector || - this is PanDetector || + if (this is PanDetector || this is ScaleDetector || this is MultiTapListener || this is MultiTouchDragDetector) { diff --git a/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart b/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart index 046c29ee5fc..ee285c11ce3 100644 --- a/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart +++ b/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart @@ -44,30 +44,6 @@ class GestureDetectorBuilder { } void initializeGestures(Game game) { - if (game is VerticalDragDetector) { - register( - VerticalDragGestureRecognizer.new, - (VerticalDragGestureRecognizer instance) { - instance.onDown = game.handleVerticalDragDown; - instance.onStart = game.handleVerticalDragStart; - instance.onUpdate = game.handleVerticalDragUpdate; - instance.onEnd = game.handleVerticalDragEnd; - instance.onCancel = game.onVerticalDragCancel; - }, - ); - } - if (game is HorizontalDragDetector) { - register( - HorizontalDragGestureRecognizer.new, - (HorizontalDragGestureRecognizer instance) { - instance.onDown = game.handleHorizontalDragDown; - instance.onStart = game.handleHorizontalDragStart; - instance.onUpdate = game.handleHorizontalDragUpdate; - instance.onEnd = game.handleHorizontalDragEnd; - instance.onCancel = game.onHorizontalDragCancel; - }, - ); - } if (game is PanDetector) { register( PanGestureRecognizer.new, diff --git a/packages/flame/lib/src/gestures/detectors.dart b/packages/flame/lib/src/gestures/detectors.dart index 48bcc0520c5..7157a65ab46 100644 --- a/packages/flame/lib/src/gestures/detectors.dart +++ b/packages/flame/lib/src/gestures/detectors.dart @@ -2,54 +2,6 @@ import 'package:flame/src/game/game.dart'; import 'package:flame/src/gestures/events.dart'; import 'package:flutter/gestures.dart'; -mixin VerticalDragDetector on Game { - void onVerticalDragDown(DragDownInfo info) {} - void onVerticalDragStart(DragStartInfo info) {} - void onVerticalDragUpdate(DragUpdateInfo info) {} - void onVerticalDragEnd(DragEndInfo info) {} - void onVerticalDragCancel() {} - - void handleVerticalDragDown(DragDownDetails details) { - onVerticalDragDown(DragDownInfo.fromDetails(this, details)); - } - - void handleVerticalDragStart(DragStartDetails details) { - onVerticalDragStart(DragStartInfo.fromDetails(this, details)); - } - - void handleVerticalDragUpdate(DragUpdateDetails details) { - onVerticalDragUpdate(DragUpdateInfo.fromDetails(this, details)); - } - - void handleVerticalDragEnd(DragEndDetails details) { - onVerticalDragEnd(DragEndInfo.fromDetails(details)); - } -} - -mixin HorizontalDragDetector on Game { - void onHorizontalDragDown(DragDownInfo info) {} - void onHorizontalDragStart(DragStartInfo info) {} - void onHorizontalDragUpdate(DragUpdateInfo info) {} - void onHorizontalDragEnd(DragEndInfo info) {} - void onHorizontalDragCancel() {} - - void handleHorizontalDragDown(DragDownDetails details) { - onHorizontalDragDown(DragDownInfo.fromDetails(this, details)); - } - - void handleHorizontalDragStart(DragStartDetails details) { - onHorizontalDragStart(DragStartInfo.fromDetails(this, details)); - } - - void handleHorizontalDragUpdate(DragUpdateDetails details) { - onHorizontalDragUpdate(DragUpdateInfo.fromDetails(this, details)); - } - - void handleHorizontalDragEnd(DragEndDetails details) { - onHorizontalDragEnd(DragEndInfo.fromDetails(details)); - } -} - mixin PanDetector on Game { void onPanDown(DragDownInfo info) {} void onPanStart(DragStartInfo info) {} diff --git a/packages/flame/test/game/game_widget/game_widget_drag_test.dart b/packages/flame/test/game/game_widget/game_widget_drag_test.dart index 326ab00c8e2..122e79eaae8 100644 --- a/packages/flame/test/game/game_widget/game_widget_drag_test.dart +++ b/packages/flame/test/game/game_widget/game_widget_drag_test.dart @@ -3,36 +3,6 @@ import 'package:flame/input.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; -class _HorizontalDragGame extends FlameGame with HorizontalDragDetector { - bool horizontalDragStarted = false; - bool horizontalDragEnded = false; - - @override - void onHorizontalDragStart(_) { - horizontalDragStarted = true; - } - - @override - void onHorizontalDragEnd(_) { - horizontalDragEnded = true; - } -} - -class _VerticalDragGame extends FlameGame with VerticalDragDetector { - bool verticalDragStarted = false; - bool verticalDragEnded = false; - - @override - void onVerticalDragStart(_) { - verticalDragStarted = true; - } - - @override - void onVerticalDragEnd(_) { - verticalDragEnded = true; - } -} - class _PanGame extends FlameGame with PanDetector { bool panStarted = false; bool panEnded = false; @@ -49,40 +19,8 @@ class _PanGame extends FlameGame with PanDetector { } void main() { - final horizontalGame = FlameTester(_HorizontalDragGame.new); - final verticalGame = FlameTester(_VerticalDragGame.new); final panGame = FlameTester(_PanGame.new); - group('GameWidget - HorizontalDragDetector', () { - horizontalGame.testGameWidget( - 'register drags', - verify: (game, tester) async { - await tester.drag( - find.byGame<_HorizontalDragGame>(), - const Offset(50, 0), - ); - - expect(game.horizontalDragStarted, isTrue); - expect(game.horizontalDragEnded, isTrue); - }, - ); - }); - - group('GameWidget - VerticalDragDetector', () { - verticalGame.testGameWidget( - 'register drags', - verify: (game, tester) async { - await tester.drag( - find.byGame<_VerticalDragGame>(), - const Offset(50, 0), - ); - - expect(game.verticalDragStarted, isTrue); - expect(game.verticalDragEnded, isTrue); - }, - ); - }); - group('GameWidget - PanDetector', () { panGame.testGameWidget( 'register drags', diff --git a/packages/flame/test/gestures/detectors_test.dart b/packages/flame/test/gestures/detectors_test.dart index 8945091987c..f378c5d3130 100644 --- a/packages/flame/test/gestures/detectors_test.dart +++ b/packages/flame/test/gestures/detectors_test.dart @@ -33,128 +33,6 @@ void main() { ); }); - group('VerticalDragDetector', () { - final verticalDragGame = FlameTester(_VerticalDragDetectorGame.new); - - verticalDragGame.testGameWidget( - 'can register vertical drag', - verify: (game, tester) async { - await tester.dragFrom(const Offset(10, 10), const Offset(10, 50)); - - expect(game.hasVerticalDragDown, isTrue); - expect(game.hasVerticalDragStart, isTrue); - expect(game.hasVerticalDragUpdate, isTrue); - expect(game.hasVerticalDragEnd, isTrue); - }, - ); - - testWithGame<_VerticalDragDetectorGame>( - 'can be Vertical Dragged Down', - _VerticalDragDetectorGame.new, - (game) async { - await game.ready(); - game.handleVerticalDragDown(DragDownDetails()); - - expect(game.hasVerticalDragDown, isTrue); - }, - ); - - testWithGame<_VerticalDragDetectorGame>( - 'can be Vertical Dragged Start', - _VerticalDragDetectorGame.new, - (game) async { - await game.ready(); - - game.handleVerticalDragStart(DragStartDetails()); - - expect(game.hasVerticalDragStart, isTrue); - }, - ); - - testWithGame<_VerticalDragDetectorGame>( - 'can be Vertical Dragged Update', - _VerticalDragDetectorGame.new, - (game) async { - game.handleVerticalDragUpdate( - DragUpdateDetails(globalPosition: const Offset(10, 10)), - ); - - expect(game.hasVerticalDragUpdate, isTrue); - }, - ); - - testWithGame<_VerticalDragDetectorGame>( - 'can be Vertical Dragged End', - _VerticalDragDetectorGame.new, - (game) async { - game.handleVerticalDragEnd(DragEndDetails()); - - expect(game.hasVerticalDragEnd, isTrue); - }, - ); - }); - - group('HorizontalDragDetector', () { - final horizontalDragGame = FlameTester(_HorizontalDragDetectorGame.new); - - horizontalDragGame.testGameWidget( - 'can register horizontal drag', - verify: (game, tester) async { - await tester.dragFrom(const Offset(10, 10), const Offset(50, 10)); - - expect(game.hasHorizontalDragDown, isTrue); - expect(game.hasHorizontalDragUpdate, isTrue); - expect(game.hasHorizontalDragEnd, isTrue); - }, - ); - - testWithGame<_HorizontalDragDetectorGame>( - 'can be horizontal Dragged Down', - _HorizontalDragDetectorGame.new, - (game) async { - await game.ready(); - game.handleHorizontalDragDown(DragDownDetails()); - - expect(game.hasHorizontalDragDown, isTrue); - }, - ); - - testWithGame<_HorizontalDragDetectorGame>( - 'can be horizontal Dragged Start', - _HorizontalDragDetectorGame.new, - (game) async { - await game.ready(); - game.handleHorizontalDragStart(DragStartDetails()); - - expect(game.hasHorizontalDragStart, isTrue); - }, - ); - - testWithGame<_HorizontalDragDetectorGame>( - 'can be horizontal Dragged update', - _HorizontalDragDetectorGame.new, - (game) async { - await game.ready(); - game.handleHorizontalDragUpdate( - DragUpdateDetails(globalPosition: const Offset(10, 10)), - ); - - expect(game.hasHorizontalDragUpdate, isTrue); - }, - ); - - testWithGame<_HorizontalDragDetectorGame>( - 'can be horizontal Dragged End', - _HorizontalDragDetectorGame.new, - (game) async { - await game.ready(); - game.handleHorizontalDragEnd(DragEndDetails()); - - expect(game.hasHorizontalDragEnd, isTrue); - }, - ); - }); - group('PanDetector', () { final panGame = FlameTester(_PanDetectorGame.new); @@ -313,73 +191,6 @@ void main() { }); } -class _HorizontalDragDetectorGame extends FlameGame - with HorizontalDragDetector { - bool hasHorizontalDragDown = false; - bool hasHorizontalDragCancel = false; - bool hasHorizontalDragEnd = false; - bool hasHorizontalDragUpdate = false; - bool hasHorizontalDragStart = false; - - @override - void onHorizontalDragDown(DragDownInfo info) { - hasHorizontalDragDown = true; - } - - @override - void onHorizontalDragStart(DragStartInfo info) { - hasHorizontalDragStart = true; - } - - @override - void onHorizontalDragUpdate(DragUpdateInfo info) { - hasHorizontalDragUpdate = true; - } - - @override - void onHorizontalDragEnd(DragEndInfo info) { - hasHorizontalDragEnd = true; - } - - @override - void onHorizontalDragCancel() { - hasHorizontalDragCancel = true; - } -} - -class _VerticalDragDetectorGame extends FlameGame with VerticalDragDetector { - bool hasVerticalDragDown = false; - bool hasVerticalDragCancel = false; - bool hasVerticalDragEnd = false; - bool hasVerticalDragUpdate = false; - bool hasVerticalDragStart = false; - - @override - void onVerticalDragDown(DragDownInfo info) { - hasVerticalDragDown = true; - } - - @override - void onVerticalDragCancel() { - hasVerticalDragCancel = true; - } - - @override - void onVerticalDragEnd(DragEndInfo info) { - hasVerticalDragEnd = true; - } - - @override - void onVerticalDragUpdate(DragUpdateInfo info) { - hasVerticalDragUpdate = true; - } - - @override - void onVerticalDragStart(DragStartInfo info) { - hasVerticalDragStart = true; - } -} - class _PanDetectorGame extends FlameGame with PanDetector { bool hasPanDown = false; bool hasPanCancel = false; From 769b0f1b7568c477dc1473226a76715302edfcd7 Mon Sep 17 00:00:00 2001 From: Luan Nico Date: Tue, 11 Aug 2026 01:39:56 -0400 Subject: [PATCH 2/2] fix typo --- doc/flame/migration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/flame/migration.md b/doc/flame/migration.md index 4949be29451..9b74ecfee64 100644 --- a/doc/flame/migration.md +++ b/doc/flame/migration.md @@ -35,7 +35,7 @@ class MyGame extends FlameGame with DragCallbacks { } ``` -If you specifically need the arena behaviour, wrap your `GameWidget` in Flutter's own +If you specifically need the arena behavior, wrap your `GameWidget` in Flutter's own [`GestureDetector`](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html) and use its `onVerticalDragUpdate` / `onHorizontalDragUpdate` callbacks.