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 6489374760f..3f465f35837 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 { 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 bb05312471f..c8b15a865b1 100644 --- a/packages/flame/lib/src/events/callbacks/drag_callbacks.dart +++ b/packages/flame/lib/src/events/callbacks/drag_callbacks.dart @@ -68,11 +68,13 @@ mixin DragCallbacks on Component { 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 3481232abf0..92f95912cfb 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 { 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 5cbeaea0ad7..bf26fd890e5 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 { 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 4c898ed3658..cf28c818fea 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 { 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 dd5eecba7d5..398b316fba0 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) { // Deprecated game-level detector mixins handle events for the entire @@ -262,6 +276,9 @@ class FlameGame extends ComponentTreeRoot this is MultiTouchDragDetector) { return true; } + if (_pointerEventHandlerCount == 0) { + return false; + } for (final component in super.componentsAtPoint(position)) { if (component is TapCallbacks || component is DragCallbacks ||