Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
01f3bf4
feat: Add cursor components mixin to Game
garysm Jul 25, 2022
77ac85d
Merge remote-tracking branch 'origin' into cursor-handler-components
garysm Aug 5, 2022
ceb61bc
Fix too long lines
spydon Aug 12, 2022
847ba14
Merge branch 'main' into cursor-handler-components
spydon Aug 12, 2022
01d5b83
Merge branch 'main' into cursor-handler-components
garysm Aug 20, 2022
84dc8b3
Add example for CursorHandler components
garysm Aug 23, 2022
c70680b
feat: Add cursor components mixin to Game
garysm Jul 25, 2022
aab7e10
Fix too long lines
spydon Aug 12, 2022
8a52989
Add example for CursorHandler components
garysm Aug 23, 2022
69af8bf
Merge branch 'cursor-handler-components' of https://github.com/garysm…
garysm Aug 30, 2022
316dd3f
rename example
garysm Aug 30, 2022
b229f0c
Add mouse movement to docs
garysm Aug 30, 2022
fa4d26a
Merge branch 'main' into cursor-handler-components
garysm Aug 31, 2022
446e80b
Merge branch 'main' into cursor-handler-components
spydon Sep 12, 2022
dde9dbb
Merge branch 'main' into cursor-handler-components
spydon Sep 16, 2022
1c19e31
Merge branch 'main' into cursor-handler-components
spydon Sep 27, 2022
1d26c18
update docs for linting
garysm Nov 21, 2022
ce40df1
Update doc/flame/inputs/gesture-input.md
garysm Nov 27, 2022
cadf718
Merge branch 'main' into cursor-handler-components
garysm Nov 27, 2022
4293baa
update doc for linting and admonition
garysm Nov 27, 2022
0ebb400
Add blank line in doc
garysm Nov 27, 2022
eb6a8bd
Merge branch 'main' into cursor-handler-components
garysm Apr 28, 2023
fdfbb76
Merge branch 'main' of https://github.com/garysm/flame into cursor-ha…
garysm Jun 6, 2023
27f536a
Merge branch 'main' of https://github.com/garysm/flame into cursor-ha…
garysm Jun 10, 2023
0f0db95
Wip
garysm Jun 13, 2023
135fc39
fix export error
garysm Jun 13, 2023
1f5d375
Merge branch 'main' into cursor-handler-components
garysm Jun 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions doc/flame/inputs/gesture_input.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,3 +515,44 @@ More information about how to define hitboxes can be found in the hitbox section

An example of how to use it can be seen
[here](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/input/gesture_hitboxes_example.dart).


### MouseMovement on the game level

To give a `Game` class the ability to handle mouse movement/hover events,
use the `MouseMovementDetector` mixin.

You can then override an `onMouseMove` method. This method receives
[`PointerHoverInfo`](https://pub.dev/documentation/flame/latest/events/PointerHoverInfo-class.html)
which provides the position of the hover event, as well as the raw
[`PointerHoverEvent`](https://api.flutter.dev/flutter/gestures/PointerHoverEvent-class.html)

```{warning}
This should not be used on platforms that do not support mouse cursors.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this warning more clear as to what happens?
is the handler ignored?
or will it error?
that is relevant to multi-platform games

```

Example:

```dart
class MouseCursorExample extends FlameGame with MouseMovementDetector {
// ...
@override
void onMouseMove(PointerHoverInfo info) {
print('X: ${info.eventPosition.game.x}');
print('Y: ${info.eventPosition.game.y}');
}
}

```


### MouseMovement on the component level

To receive mouse movement/hover events in components, use the `HasCursorHandlerComponents`
mixin on any `Game` sub class first, and remove the `MouseMovementDetector` mixin (if present).

Then, use the `CursorHandler` mixin on any `Component` sub class.

See
[here](https://github.com/flame-engine/flame/blob/main/examples/lib/stores/input/mouse_movement_components_example.dart)
for an example.
7 changes: 7 additions & 0 deletions examples/lib/stories/input/input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ void addInputStories(Dashbook dashbook) {
codeLink: baseLink('input/mouse_movement_example.dart'),
info: MouseMovementExample.description,
)
// TODO: Add example
// ..add(
// 'Mouse Movement (Component)',
// (_) => GameWidget(game: MouseMovementComponentsExample()),
// codeLink: baseLink('input/mouse_movement_listener_example.dart'),
// info: MouseMovementComponentsExample.description,
// )
..add(
'Mouse Cursor',
(_) => GameWidget(
Expand Down
72 changes: 72 additions & 0 deletions examples/lib/stories/input/mouse_movement_components_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// import 'dart:math';

// import 'package:flame/components.dart';
// import 'package:flame/events.dart';
// import 'package:flame/game.dart';
// import 'package:flutter/material.dart';

// class MouseMovementComponentsExample extends FlameGame
// with HasCursorHandlerComponents {
// static const String description = '''
// This example shows how to handle mouse movement using `CursorHandler` Components.\n\n
// Moving the mouse around the canvas changes the angle of each Component, and causes
// the line drawn on them to face towards the mouse's position.
// ''';

// @override
// Future<void> onLoad() async {
// add(
// CursorFollowerCircle(
// radius: 20.0,
// )..position = size / 2,
// );
// add(
// CursorFollowerCircle(
// radius: 20.0,
// )..position = Vector2(100.0, 100.0),
// );
// }
// }

// class CursorFollowerCircle extends PositionComponent with CursorHandler {
// final double _radius;

// final Paint _paint;

// CursorFollowerCircle({required double radius})
// : _radius = radius,
// _paint = Paint()..color = const Color(0xFF80C080),
// super(
// size: Vector2.all(2 * radius),
// anchor: Anchor.center,
// );

// @override
// bool onMouseMove(PointerHoverInfo info) {
// final gameMousePositionX = info.eventPosition.game.x;

// final gameMousePositionY = info.eventPosition.game.y;

// angle =
// atan2(gameMousePositionY - position.y, gameMousePositionX - position.x);
// return super.onMouseMove(info);
// }

// @override
// void render(Canvas canvas) {
// super.render(canvas);

// canvas.drawCircle(
// Offset(_radius, _radius),
// _radius,
// _paint,
// );
// canvas.drawLine(
// Offset(_radius, _radius),
// Offset(_radius * 3.0, _radius),
// Paint()
// ..color = const Color(0xFFFFFFFF)
// ..strokeWidth = 2.0,
// );
// }
// }
1 change: 1 addition & 0 deletions packages/flame/lib/components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export 'src/components/input/joystick_component.dart';
export 'src/components/input/keyboard_listener_component.dart';
export 'src/components/isometric_tile_map_component.dart';
export 'src/components/mixins/component_viewport_margin.dart';
export 'src/components/mixins/cursor_handler.dart';
export 'src/components/mixins/draggable.dart';
export 'src/components/mixins/gesture_hitboxes.dart';
export 'src/components/mixins/has_ancestor.dart';
Expand Down
8 changes: 8 additions & 0 deletions packages/flame/lib/src/components/mixins/cursor_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:flame/components.dart';
import 'package:flame/src/gestures/events.dart';

mixin CursorHandler on Component {
bool onMouseMove(PointerHoverInfo info) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/events/flame_game_mixins/cursor_hover_dispatcher.dart';
import 'package:flame/src/events/messages/cursor_hover_event.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:meta/meta.dart';

mixin CursorHoverCallbacks on Component {
void onMouseMove(CursorHoverEvent event) {}

@override
@mustCallSuper
void onMount() {
super.onMount();
final game = findGame()! as FlameGame;
if (game.firstChild<CursorHoverDispatcher>() == null) {
game.add(CursorHoverDispatcher());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/events/component_mixins/cursor_hover_callbacks.dart';
import 'package:flame/src/events/messages/cursor_hover_event.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';

@internal
class CursorHoverDispatcher extends Component {
bool _eventHandlerRegistered = false;
FlameGame get game => parent! as FlameGame;

@mustCallSuper
void onMouseMove(CursorHoverEvent event) {
event.deliverAtPoint(
rootComponent: game,
eventHandler: (CursorHoverCallbacks component) {
component.onMouseMove(event);
},
);
}

@internal
void handleMouseMove(int pointerId, PointerHoverEvent pointerHoverEvent) {
onMouseMove(CursorHoverEvent(pointerId, pointerHoverEvent));
}

@override
void onMount() {
if (game.firstChild<CursorHoverDispatcher>() == null) {
// TODO: Add detector to game
// game.gestureDetectors.add(
// PointerHoverEventListener.new,
// () {},
// );
} else {
removeFromParent();
}
}
}
34 changes: 34 additions & 0 deletions packages/flame/lib/src/events/messages/cursor_hover_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:flame/image_composition.dart';
import 'package:flame/src/events/messages/position_event.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';

import 'package:flutter/gestures.dart';

class CursorHoverEvent extends PositionEvent {
CursorHoverEvent(this.pointerId, PointerHoverEvent pointerHoverEvent)
: deviceKind = pointerHoverEvent.kind,
super(
canvasPosition: pointerHoverEvent.localPosition.toVector2(),
devicePosition: pointerHoverEvent.position.toVector2(),
);

final int pointerId;

final PointerDeviceKind deviceKind;

PointerHoverInfo asInfo(Game game) {
return PointerHoverInfo.fromDetails(
game,
PointerHoverEvent(
position: devicePosition.toOffset(),
kind: deviceKind,
),
);
}

@override
String toString() => 'CursorHoverEvent(canvasPosition: $canvasPosition, '
'devicePosition: $devicePosition, '
'pointerId: $pointerId, deviceKind: $deviceKind)';
}