Closed seth35us closed 5 years ago
I had a similar issue with a PanGestureRecognizer a few hours ago. I figured out that everything works as expected when setting the event handler to null.
Try removing the GestureRecognizer like this:
tapper.onTapDown = null;
Flame.util.removeGestureRecognizer(tapper);
You don't have to dispose the tapper because that's what the removeGestureRecognizer method does. (check https://github.com/flame-engine/flame/blob/master/lib/util.dart#L133)
Anyway, this isn't really intuitive if you ask me and I think that the removeGestureRecognizer method should also set the handlers to null.
Thanks @r1sim, but this didn't work. I tried
_tapper.onTapDown = null;
Flame.util.removeGestureRecognizer(_tapper);
_tapper.dispose();
_tapper = null;
_tapDownCallBack = null;
The _tapper and _tapDownCallBack are defined only once in the init of a singleton class. I know you said that I don't have to dispose the tapper, but it didn't make a difference either way, so I left it in for good luck. I will remove it later if I can figure out how to get rid of the tapper.
_tapper = new TapGestureRecognizer();
_tapDownCallBack = (TapDownDetails evt) => handleInput(evt.globalPosition);
I checked your example project and got it to work.
You passed a new TapGestureRecognizer
instance instead of tapper
when calling the addGestureRecognizer method.
So when you change:
void _initTapHandlers() {
print("Init tap handler ${super.toString() + " " + hashCode.toString()}");
tapper = new TapGestureRecognizer();
Flame.util.addGestureRecognizer(new TapGestureRecognizer()
..onTapDown = (TapDownDetails evt) => handleInput(evt.globalPosition));
isInitialized = true;
}
to:
void _initTapHandlers() {
print("Init tap handler ${super.toString() + " " + hashCode.toString()}");
tapper = new TapGestureRecognizer();
tapper.onTapDown = handleInput;
Flame.util.addGestureRecognizer(tapper);
isInitialized = true;
}
and change handleInput(Offset globalPosition)
to handleInput(TapDownDetails details)
it should work.
@r1sim Works perfectly! Thank you for your help.
@r1sim One other issue. When I add the addGestureRecognizer the second time the tap is extremely delayed and sometimes does not even fire.
Here is the relevant code:
factory MathBlocksGame({MathBlocksUIState uiState}) {
_singleton.ui = uiState;
_singleton.ui.currentScreen = UIScreen.home;
_singleton.initialize();
if (_singleton.isTapperInitialized) return _singleton;
_singleton._initTapHandlers();
return _singleton;
}
void _initTapHandlers() {
print("Init tap handler ${super.toString() + " " + hashCode.toString()}");
_tapper = new TapGestureRecognizer();
_tapper.onTapDown = handleInput;
Flame.util.addGestureRecognizer(_tapper);
isTapperInitialized = true;
}
void dispose() {
_disposeTapper();
}
void _disposeTapper() {
if (_tapper != null) {
print(
"Dispose tap handler ${super.toString() + " " + hashCode.toString()}");
_tapper.onTapDown = null;
Flame.util.removeGestureRecognizer(_tapper);
}
isTapperInitialized = false;
}
void handleInput(TapDownDetails details) {
print("On Tap Down ${super.toString() + " " + hashCode.toString()}");
}
@seth35us The addGestureRecognizer can be a little cryptic sometimes and lead to situations like the one you are facing, we are even thinking on maybe deprecate that method and create a new API.
In the meantime, I strongly suggest you using GestureDetector
widget to wrap your game and use it to detect the gestures, since it is a widget, the callbacks should be destroyed alongside the widget, when it is removed from the widget tree, you can see an example of that here: https://github.com/fireslime/rogue_shooter/blob/master/lib/main.dart#L27
Great suggestion @erickzanardo. Here is my final code:
void initState() {
super.initState();
_initialize();
}
Future _initialize() async {
gameUI = MathBlocksUI();
game = MathBlocksGame(uiState: gameUI.state);
gameUI.state.game = game;
setState(() {});
}
Widget build(BuildContext context) {
return Scaffold(
body: (game == null || gameUI == null)
? Align(alignment: Alignment.center, child: CircularProgressIndicator())
: Stack(
fit: StackFit.expand,
children: <Widget>[
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: game.handleInput,
child: game.widget,
),
),
Positioned.fill(
child: gameUI,
),
],
));
}
I am navigating between a main page and several games. I am unable to remove the gesture recognizer when navigating away from the game widget. I have tried both methods below and created a singleton class, but the gesture recognizer won't go away. Flame.util.removeGestureRecognizer(tapper); tapper.dispose();
I am including a basic implementation to recreate the issue. As you can see the OnTap event is still occurring on the main page. I have confirmed that there is only one instance of the game running and the gesture recognizer is only registered once. I tried to remove the gesture recognizer on every tap event, just for good luck, but it didn't work. I am pasting the game class in addition to the zipped file.
import 'dart:ui';
import 'package:flame/flame.dart'; import 'package:flame/game.dart'; import 'package:flutter/gestures.dart';
class MathBlocksGame extends BaseGame { static final MathBlocksGame _singleton = new MathBlocksGame._internal(); MathBlocksGame._internal() { print('MathBlocksGame contructor called'); } static MathBlocksGame get instance => _singleton; bool isInitialized = false; TapGestureRecognizer tapper;
factory MathBlocksGame() { if (_singleton.isInitialized) return _singleton;
}
void _initTapHandlers() { print("Init tap handler ${super.toString() + " " + hashCode.toString()}"); tapper = new TapGestureRecognizer(); Flame.util.addGestureRecognizer(new TapGestureRecognizer() ..onTapDown = (TapDownDetails evt) => handleInput(evt.globalPosition)); isInitialized = true; }
void dispose() { Flame.util.removeGestureRecognizer(tapper); tapper.dispose(); }
void handleInput(Offset globalPosition) { print("On Tap Down ${super.toString() + " " + hashCode.toString()}");
} }
delete_me.zip