Draggables weren't using the new coordinate system (#777)

* refactoring drag start events

* Fixing joystick, adding tests and examples

* format fixes
This commit is contained in:
Erick
2021-04-30 10:01:42 -03:00
committed by GitHub
parent d9e0acd3ff
commit 0cb64fb57f
11 changed files with 159 additions and 56 deletions

View File

@ -52,7 +52,17 @@ void addControlsStories(Dashbook dashbook) {
) )
..add( ..add(
'Draggables', 'Draggables',
(_) => GameWidget(game: DraggablesGame()), (context) {
return GameWidget(
game: DraggablesGame(
zoom: context.listProperty(
'zoom',
1,
[0.5, 1, 1.5],
),
),
);
},
codeLink: baseLink('gestures/draggables.dart'), codeLink: baseLink('gestures/draggables.dart'),
) )
..add( ..add(

View File

@ -27,8 +27,8 @@ class DraggableSquare extends PositionComponent
} }
@override @override
bool onDragStart(int pointerId, Vector2 startPosition) { bool onDragStart(int pointerId, DragStartInfo info) {
dragDeltaPosition = startPosition - position; dragDeltaPosition = info.eventPosition.game - position;
return false; return false;
} }
@ -57,8 +57,13 @@ class DraggableSquare extends PositionComponent
} }
class DraggablesGame extends BaseGame with HasDraggableComponents { class DraggablesGame extends BaseGame with HasDraggableComponents {
final double zoom;
DraggablesGame({required this.zoom});
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
camera.zoom = zoom;
add(DraggableSquare()); add(DraggableSquare());
add(DraggableSquare()..y = 350); add(DraggableSquare()..y = 350);
} }

View File

@ -39,9 +39,9 @@ class MultitapAdvancedGame extends BaseGame
} }
@override @override
void onDragStart(int pointerId, Vector2 position) { void onDragStart(int pointerId, DragStartInfo info) {
end = null; end = null;
start = position; start = info.eventPosition.game;
} }
@override @override

View File

@ -163,13 +163,13 @@ class JoystickAction extends BaseComponent with Draggable, HasGameRef {
} }
@override @override
bool onDragStart(int pointerId, Vector2 startPosition) { bool onDragStart(int pointerId, DragStartInfo info) {
if (_dragging) { if (_dragging) {
return true; return true;
} }
if (enableDirection) { if (enableDirection) {
_dragPosition = startPosition; _dragPosition = info.eventPosition.widget;
_dragging = true; _dragging = true;
} }
_sendEvent(ActionEvent.down); _sendEvent(ActionEvent.down);

View File

@ -130,11 +130,11 @@ class JoystickDirectional extends BaseComponent with Draggable, HasGameRef {
} }
@override @override
bool onDragStart(int pointerId, Vector2 startPosition) { bool onDragStart(int pointerId, DragStartInfo info) {
_updateDirectionalRect(startPosition); _updateDirectionalRect(info.eventPosition.widget);
if (!_dragging) { if (!_dragging) {
_dragging = true; _dragging = true;
_dragPosition = startPosition; _dragPosition = info.eventPosition.widget;
return true; return true;
} }
return false; return false;

View File

@ -1,20 +1,19 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../extensions.dart';
import '../../game/base_game.dart'; import '../../game/base_game.dart';
import '../../gestures/events.dart'; import '../../gestures/events.dart';
import '../base_component.dart'; import '../base_component.dart';
mixin Draggable on BaseComponent { mixin Draggable on BaseComponent {
bool onDragStart(int pointerId, Vector2 startPosition) { bool onDragStart(int pointerId, DragStartInfo info) {
return true; return true;
} }
bool onDragUpdate(int pointerId, DragUpdateInfo details) { bool onDragUpdate(int pointerId, DragUpdateInfo info) {
return true; return true;
} }
bool onDragEnd(int pointerId, DragEndInfo details) { bool onDragEnd(int pointerId, DragEndInfo info) {
return true; return true;
} }
@ -25,10 +24,10 @@ mixin Draggable on BaseComponent {
final List<int> _currentPointerIds = []; final List<int> _currentPointerIds = [];
bool _checkPointerId(int pointerId) => _currentPointerIds.contains(pointerId); bool _checkPointerId(int pointerId) => _currentPointerIds.contains(pointerId);
bool handleDragStart(int pointerId, Vector2 startPosition) { bool handleDragStart(int pointerId, DragStartInfo info) {
if (containsPoint(startPosition)) { if (containsPoint(info.eventPosition.game)) {
_currentPointerIds.add(pointerId); _currentPointerIds.add(pointerId);
return onDragStart(pointerId, startPosition); return onDragStart(pointerId, info);
} }
return true; return true;
} }
@ -59,8 +58,8 @@ mixin Draggable on BaseComponent {
mixin HasDraggableComponents on BaseGame { mixin HasDraggableComponents on BaseGame {
@mustCallSuper @mustCallSuper
void onDragStart(int pointerId, Vector2 startPosition) { void onDragStart(int pointerId, DragStartInfo info) {
_onGenericEventReceived((c) => c.handleDragStart(pointerId, startPosition)); _onGenericEventReceived((c) => c.handleDragStart(pointerId, info));
} }
@mustCallSuper @mustCallSuper

View File

@ -192,14 +192,28 @@ Widget applyAdvancedGesturesDetectors(Game game, Widget child) {
); );
} }
void addDragRecognizer(Drag Function(int, Vector2) config) { void addDragRecognizer(Game game, Drag Function(int, DragStartInfo) config) {
addAndConfigureRecognizer( addAndConfigureRecognizer(
() => ImmediateMultiDragGestureRecognizer(), () => ImmediateMultiDragGestureRecognizer(),
(ImmediateMultiDragGestureRecognizer instance) { (ImmediateMultiDragGestureRecognizer instance) {
instance.onStart = (Offset o) { instance.onStart = (Offset o) {
final pointerId = lastGeneratedDragId++; final pointerId = lastGeneratedDragId++;
final position = game.convertGlobalToLocalCoordinate(o.toVector2());
return config(pointerId, position); final global = o;
final local = game
.convertGlobalToLocalCoordinate(
global.toVector2(),
)
.toOffset();
final details = DragStartDetails(
localPosition: local,
globalPosition: global,
);
return config(
pointerId,
DragStartInfo.fromDetails(game, details),
);
}; };
}, },
); );
@ -228,15 +242,15 @@ Widget applyAdvancedGesturesDetectors(Game game, Widget child) {
} }
if (game is MultiTouchDragDetector) { if (game is MultiTouchDragDetector) {
addDragRecognizer((int pointerId, Vector2 position) { addDragRecognizer(game, (int pointerId, DragStartInfo info) {
game.onDragStart(pointerId, position); game.onDragStart(pointerId, info);
return _DragEvent(game) return _DragEvent(game)
..onUpdate = ((details) => game.onDragUpdate(pointerId, details)) ..onUpdate = ((details) => game.onDragUpdate(pointerId, details))
..onEnd = ((details) => game.onDragEnd(pointerId, details)) ..onEnd = ((details) => game.onDragEnd(pointerId, details))
..onCancel = (() => game.onDragCancel(pointerId)); ..onCancel = (() => game.onDragCancel(pointerId));
}); });
} else if (game is HasDraggableComponents) { } else if (game is HasDraggableComponents) {
addDragRecognizer((int pointerId, Vector2 position) { addDragRecognizer(game, (int pointerId, DragStartInfo position) {
game.onDragStart(pointerId, position); game.onDragStart(pointerId, position);
return _DragEvent(game) return _DragEvent(game)
..onUpdate = ((details) => game.onDragUpdate(pointerId, details)) ..onUpdate = ((details) => game.onDragUpdate(pointerId, details))

View File

@ -1,4 +1,3 @@
import '../../extensions.dart';
import '../game/game.dart'; import '../game/game.dart';
import 'events.dart'; import 'events.dart';
@ -11,7 +10,7 @@ mixin MultiTouchTapDetector on Game {
} }
mixin MultiTouchDragDetector on Game { mixin MultiTouchDragDetector on Game {
void onDragStart(int pointerId, Vector2 startPosition) {} void onDragStart(int pointerId, DragStartInfo info) {}
void onDragUpdate(int pointerId, DragUpdateInfo info) {} void onDragUpdate(int pointerId, DragUpdateInfo info) {}
void onDragEnd(int pointerId, DragEndInfo info) {} void onDragEnd(int pointerId, DragEndInfo info) {}
void onDragCancel(int pointerId) {} void onDragCancel(int pointerId) {}

View File

@ -1,25 +0,0 @@
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:test/test.dart';
class _GameWithDraggables extends BaseGame with HasDraggableComponents {}
class _GameWithoutDraggables extends BaseGame {}
class DraggableComponent extends PositionComponent with Draggable {}
void main() {
group('draggables test', () {
test('make sure they cannot be added to invalid games', () async {
final game1 = _GameWithDraggables();
// should be ok
await game1.add(DraggableComponent());
final game2 = _GameWithoutDraggables();
expect(
() => game2.add(DraggableComponent()),
isA<AssertionError>(),
);
});
});
}

View File

@ -0,0 +1,93 @@
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
class _GameWithDraggables extends BaseGame with HasDraggableComponents {}
class _GameWithoutDraggables extends BaseGame {}
class DraggableComponent extends PositionComponent with Draggable {
bool hasStartedDragging = false;
@override
bool onDragStart(int pointerId, DragStartInfo event) {
hasStartedDragging = true;
return true;
}
}
void main() {
group('draggables test', () {
test('make sure they cannot be added to invalid games', () async {
final game1 = _GameWithDraggables();
game1.onResize(Vector2.all(100));
// should be ok
await game1.add(DraggableComponent());
final game2 = _GameWithoutDraggables();
game2.onResize(Vector2.all(100));
var hasError = false;
try {
await game2.add(DraggableComponent());
} catch (e) {
hasError = true;
}
expect(hasError, true);
});
test('can be dragged', () async {
final game = _GameWithDraggables();
game.onResize(Vector2.all(100));
final component = DraggableComponent()
..x = 10
..y = 10
..width = 10
..height = 10;
await game.add(component);
// So component is added
game.update(0.01);
game.onDragStart(
1,
DragStartInfo.fromDetails(
game,
DragStartDetails(
localPosition: const Offset(12, 12),
globalPosition: const Offset(12, 12),
),
),
);
expect(component.hasStartedDragging, true);
});
test('when the game has camera zoom, can be dragged', () async {
final game = _GameWithDraggables();
game.onResize(Vector2.all(100));
final component = DraggableComponent()
..x = 10
..y = 10
..width = 10
..height = 10;
await game.add(component);
game.camera.zoom = 1.5;
// So component is added
game.update(0.01);
game.onDragStart(
1,
DragStartInfo.fromDetails(
game,
DragStartDetails(
localPosition: const Offset(12, 12),
globalPosition: const Offset(12, 12),
),
),
);
expect(component.hasStartedDragging, true);
});
});
}

View File

@ -12,14 +12,22 @@ void main() {
group('tapables test', () { group('tapables test', () {
test('make sure they cannot be added to invalid games', () async { test('make sure they cannot be added to invalid games', () async {
final game1 = _GameWithTapables(); final game1 = _GameWithTapables();
game1.onResize(Vector2.all(100));
// should be ok // should be ok
await game1.add(TapableComponent()); await game1.add(TapableComponent());
final game2 = _GameWithoutTapables(); final game2 = _GameWithoutTapables();
expect( game2.onResize(Vector2.all(100));
() => game2.add(TapableComponent()),
isA<AssertionError>(), var hasError = false;
);
try {
await game2.add(TapableComponent());
} catch (e) {
hasError = true;
}
expect(hasError, true);
}); });
}); });
} }