Skip to content

Commit

Permalink
fix: Allow most basic and advanced gesture detectors together (#1208)
Browse files Browse the repository at this point in the history
Most gesture detectors work together now, except for the PanDetector or ScaleDetector together with the MultiTouchDragDetector. Maybe even the ScaleDetector will work with the MultiTouchDragDetector, will have to try.
  • Loading branch information
spydon committed Dec 16, 2021
1 parent 23b1dd8 commit 5828b6f
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 79 deletions.
81 changes: 41 additions & 40 deletions packages/flame/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,51 @@ void main() {
);
}

class Square extends PositionComponent {
/// This example simply adds a rotating white square on the screen, if you press
/// somewhere other than on the existing square another square will be added and
/// if you press on a square it will be removed.
class MyGame extends FlameGame with DoubleTapDetector, HasTappables {
bool running = true;

@override
Future<void> onLoad() async {
await super.onLoad();
add(Square(Vector2(100, 200)));
}

@override
void onTapUp(int id, TapUpInfo info) {
super.onTapUp(id, info);
final touchPoint = info.eventPosition.game;
final handled = children.any((c) => c.shouldRemove);

if (!handled) {
add(Square(touchPoint));
}
}

@override
void onDoubleTap() {
if (running) {
pauseEngine();
} else {
resumeEngine();
}

running = !running;
}
}

class Square extends PositionComponent with Tappable {
static const speed = 0.25;
static const squareSize = 128.0;

static Paint white = BasicPalette.white.paint();
static Paint red = BasicPalette.red.paint();
static Paint blue = BasicPalette.blue.paint();

Square(Vector2 position) : super(position: position);

@override
void render(Canvas c) {
c.drawRect(size.toRect(), white);
Expand All @@ -42,46 +79,10 @@ class Square extends PositionComponent {
size.setValues(squareSize, squareSize);
anchor = Anchor.center;
}
}

class MyGame extends FlameGame with DoubleTapDetector, TapDetector {
bool running = true;

@override
Future<void> onLoad() async {
await super.onLoad();
add(
Square()
..x = 100
..y = 100,
);
}

@override
void onTapUp(TapUpInfo info) {
final touchPoint = info.eventPosition.game;

final handled = children.any((c) {
if (c is PositionComponent && c.containsPoint(touchPoint)) {
remove(c);
return true;
}
return false;
});

if (!handled) {
add(Square()..position = touchPoint);
}
}

@override
void onDoubleTap() {
if (running) {
pauseEngine();
} else {
resumeEngine();
}

running = !running;
bool onTapUp(TapUpInfo info) {
removeFromParent();
return true;
}
}
4 changes: 1 addition & 3 deletions packages/flame/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
name: flame_example
description: Simple example of a Flame game

publish_to: 'none'

version: 0.1.0
publish_to: 'none'

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down
1 change: 1 addition & 0 deletions packages/flame/lib/src/components/mixins/tappable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ mixin Tappable on Component {
}
}

// TODO(spydon): these methods should return the result of propagateToChildren.
mixin HasTappables on FlameGame {
@mustCallSuper
void onTapCancel(int pointerId) {
Expand Down
33 changes: 16 additions & 17 deletions packages/flame/lib/src/game/game_widget/game_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -264,34 +264,33 @@ class _GameWidgetState<T extends Game> extends State<GameWidget<T>> {

@override
Widget build(BuildContext context) {
Widget internalGameWidget = _GameRenderObjectWidget(widget.game);

final hasBasicDetectors = hasBasicGestureDetectors(widget.game);
final hasAdvancedDetectors = hasAdvancedGesturesDetectors(widget.game);
final game = widget.game;
Widget internalGameWidget = _GameRenderObjectWidget(game);

assert(
!(hasBasicDetectors && hasAdvancedDetectors),
'''
WARNING: Both Advanced and Basic detectors detected.
Advanced detectors will override basic detectors and the later will not receive events
''',
!(game is MultiTouchDragDetector && game is PanDetector),
'WARNING: Both MultiTouchDragDetector and a PanDetector detected. '
'The MultiTouchDragDetector will override the PanDetector and it will '
'not receive events',
);

if (hasBasicDetectors) {
if (hasBasicGestureDetectors(game)) {
internalGameWidget = applyBasicGesturesDetectors(
widget.game,
game,
internalGameWidget,
);
} else if (hasAdvancedDetectors) {
}

if (hasAdvancedGestureDetectors(game)) {
internalGameWidget = applyAdvancedGesturesDetectors(
widget.game,
game,
internalGameWidget,
);
}

if (hasMouseDetectors(widget.game)) {
if (hasMouseDetectors(game)) {
internalGameWidget = applyMouseDetectors(
widget.game,
game,
internalGameWidget,
);
}
Expand All @@ -312,10 +311,10 @@ class _GameWidgetState<T extends Game> extends State<GameWidget<T>> {
child: Directionality(
textDirection: textDir,
child: Container(
color: widget.game.backgroundColor(),
color: game.backgroundColor(),
child: LayoutBuilder(
builder: (_, BoxConstraints constraints) {
widget.game.onGameResize(constraints.biggest.toVector2());
game.onGameResize(constraints.biggest.toVector2());
return FutureBuilder(
future: loaderFuture,
builder: (_, snapshot) {
Expand Down
41 changes: 22 additions & 19 deletions packages/flame/lib/src/game/game_widget/gestures.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,30 @@ import '../../gestures/detectors.dart';
import '../../gestures/events.dart';
import '../mixins/game.dart';

bool hasBasicGestureDetectors(Game game) =>
game is TapDetector ||
game is SecondaryTapDetector ||
game is DoubleTapDetector ||
game is LongPressDetector ||
game is VerticalDragDetector ||
game is HorizontalDragDetector ||
game is ForcePressDetector ||
game is PanDetector ||
game is ScaleDetector;
bool hasBasicGestureDetectors(Game game) {
return game is TapDetector ||
game is SecondaryTapDetector ||
game is DoubleTapDetector ||
game is LongPressDetector ||
game is VerticalDragDetector ||
game is HorizontalDragDetector ||
game is ForcePressDetector ||
game is PanDetector ||
game is ScaleDetector;
}

bool hasAdvancedGesturesDetectors(Game game) =>
game is MultiTouchTapDetector ||
game is MultiTouchDragDetector ||
game is HasTappables ||
game is HasDraggables;
bool hasAdvancedGestureDetectors(Game game) {
return game is MultiTouchTapDetector ||
game is MultiTouchDragDetector ||
game is HasTappables ||
game is HasDraggables;
}

bool hasMouseDetectors(Game game) =>
game is MouseMovementDetector ||
game is ScrollDetector ||
game is HasHoverables;
bool hasMouseDetectors(Game game) {
return game is MouseMovementDetector ||
game is ScrollDetector ||
game is HasHoverables;
}

Widget applyBasicGesturesDetectors(Game game, Widget child) {
return GestureDetector(
Expand Down
37 changes: 37 additions & 0 deletions packages/flame/test/game/detectors_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter_test/flutter_test.dart';

class _MultiDragPanGame extends FlameGame
with MultiTouchDragDetector, PanDetector {}

class _MultiTapDoubleTapGame extends FlameGame
with MultiTouchTapDetector, DoubleTapDetector {}

void main() {
group('apply detectors', () {
testWidgets(
'game can not have both MultiTouchDragDetector and PanDetector',
(tester) async {
await tester.pumpWidget(
GameWidget(
game: _MultiDragPanGame(),
),
);
expect(tester.takeException(), isInstanceOf<AssertionError>());
},
);

testWidgets(
'game can have both MultiTouchTapDetector and DoubleTapDetector',
(tester) async {
await tester.pumpWidget(
GameWidget(
game: _MultiTapDoubleTapGame(),
),
);
expect(tester.takeException(), null);
},
);
});
}

0 comments on commit 5828b6f

Please sign in to comment.