diff --git a/packages/flame/lib/src/events/callbacks/double_tap_callbacks.dart b/packages/flame/lib/src/events/callbacks/double_tap_callbacks.dart index eaaee2650fb..485e376d217 100644 --- a/packages/flame/lib/src/events/callbacks/double_tap_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/double_tap_callbacks.dart @@ -1,5 +1,6 @@ import 'package:flame/components.dart'; import 'package:flame/events.dart'; +import 'package:meta/meta.dart'; /// [DoubleTapCallbacks] adds the ability to receive double-tap events in a /// component. @@ -25,8 +26,17 @@ mixin DoubleTapCallbacks on Component implements PointerInputCallbacks { void onDoubleTapCancel(DoubleTapCancelEvent event) {} @override + @mustCallSuper void onMount() { super.onMount(); DoubleTapDispatcher.addDispatcher(this); + findRootGame()?.adjustPointerEventHandlerCount(1); + } + + @override + @mustCallSuper + void onRemove() { + findRootGame()?.adjustPointerEventHandlerCount(-1); + super.onRemove(); } } diff --git a/packages/flame/lib/src/events/callbacks/drag_callbacks.dart b/packages/flame/lib/src/events/callbacks/drag_callbacks.dart index c00bff2544f..040a2407654 100644 --- a/packages/flame/lib/src/events/callbacks/drag_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/drag_callbacks.dart @@ -75,11 +75,13 @@ mixin DragCallbacks on Component implements PointerInputCallbacks { hasDrag: true, hasScale: false, ); + findRootGame()?.adjustPointerEventHandlerCount(1); } @override @mustCallSuper void onRemove() { + findRootGame()?.adjustPointerEventHandlerCount(-1); MultiDragScaleDispatcher.removeDispatcher( this, hasDrag: true, diff --git a/packages/flame/lib/src/events/callbacks/scale_callbacks.dart b/packages/flame/lib/src/events/callbacks/scale_callbacks.dart index a819f616ce9..bb8c7ee7191 100644 --- a/packages/flame/lib/src/events/callbacks/scale_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/scale_callbacks.dart @@ -30,11 +30,13 @@ mixin ScaleCallbacks on Component implements PointerInputCallbacks { hasDrag: false, hasScale: true, ); + findRootGame()?.adjustPointerEventHandlerCount(1); } @override @mustCallSuper void onRemove() { + findRootGame()?.adjustPointerEventHandlerCount(-1); MultiDragScaleDispatcher.removeDispatcher( this, hasDrag: false, diff --git a/packages/flame/lib/src/events/callbacks/secondary_tap_callbacks.dart b/packages/flame/lib/src/events/callbacks/secondary_tap_callbacks.dart index 01736388b85..639e9995e04 100644 --- a/packages/flame/lib/src/events/callbacks/secondary_tap_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/secondary_tap_callbacks.dart @@ -23,5 +23,13 @@ mixin SecondaryTapCallbacks on Component implements PointerInputCallbacks { void onMount() { super.onMount(); NonPrimaryTapDispatcher.addDispatcher(this); + findRootGame()?.adjustPointerEventHandlerCount(1); + } + + @override + @mustCallSuper + void onRemove() { + findRootGame()?.adjustPointerEventHandlerCount(-1); + super.onRemove(); } } diff --git a/packages/flame/lib/src/events/callbacks/tap_callbacks.dart b/packages/flame/lib/src/events/callbacks/tap_callbacks.dart index 5733ec2a9eb..7d4a9c5cc79 100644 --- a/packages/flame/lib/src/events/callbacks/tap_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/tap_callbacks.dart @@ -23,5 +23,13 @@ mixin TapCallbacks on Component implements PointerInputCallbacks { void onMount() { super.onMount(); MultiTapDispatcher.addDispatcher(this); + findRootGame()?.adjustPointerEventHandlerCount(1); + } + + @override + @mustCallSuper + void onRemove() { + findRootGame()?.adjustPointerEventHandlerCount(-1); + super.onRemove(); } } diff --git a/packages/flame/lib/src/game/flame_game.dart b/packages/flame/lib/src/game/flame_game.dart index 32065890ec3..43cb59648a0 100644 --- a/packages/flame/lib/src/game/flame_game.dart +++ b/packages/flame/lib/src/game/flame_game.dart @@ -243,6 +243,20 @@ class FlameGame extends ComponentTreeRoot point.y < canvasSize.y; } + /// The number of currently mounted components (in this game or any nested + /// game) that can receive pointer events. Maintained by the event callback + /// mixins ([TapCallbacks], [DragCallbacks], [DoubleTapCallbacks], + /// [ScaleCallbacks], [SecondaryTapCallbacks]) on the root game, so that + /// [containsEventHandlerAt] can skip hit testing entirely for games + /// without any pointer-event handlers. + int _pointerEventHandlerCount = 0; + + @internal + void adjustPointerEventHandlerCount(int delta) { + _pointerEventHandlerCount += delta; + assert(_pointerEventHandlerCount >= 0); + } + @override bool containsEventHandlerAt(Vector2 position) { // Game-level detector mixins handle events for the entire game surface, @@ -250,6 +264,9 @@ class FlameGame extends ComponentTreeRoot if (this is PanDetector) { return true; } + if (_pointerEventHandlerCount == 0) { + return false; + } for (final component in super.componentsAtPoint(position)) { if (component is PointerInputCallbacks) { return true;