Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
56 changes: 17 additions & 39 deletions doc/flame/inputs/gesture_input.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
# Gesture Input

This is documentation for the legacy detector mixins, which are added directly to your game class.
New code should prefer the `Callbacks` mixins instead (e.g. [TapCallbacks](tap_events.md) and
[DragCallbacks](drag_events.md)) which can be added to any `Component`, including the `FlameGame`
itself.
Gesture input in Flame is handled by the `Callbacks` mixins. They can be added to any `Component`,
and since `FlameGame` is itself a `Component`, adding one to your game class works exactly as well —
no wrapper component required. Each family has its own page:

- [Tap Events](tap_events.md): `TapCallbacks`, `DoubleTapCallbacks`, and the secondary/tertiary
button variants
- [Drag Events](drag_events.md): `DragCallbacks`
- [Scale Events](scale_events.md): `ScaleCallbacks`
- [Long Press Events](long_press_events.md): `LongPressCallbacks`
- [Pointer Events](pointer_events.md): `MouseMoveCallbacks`, `HoverCallbacks`, `ScrollCallbacks`

For other input documents, see also:

- [Keyboard Input](keyboard_input.md): for keystrokes
- [Other Inputs](other_inputs.md): For joysticks, game pads, etc.


## Intro

Inside `package:flame/input.dart` you can find a set of legacy `mixin`s which can be included on
your game class instance to be able to receive touch input events. Below you can see the full
list of these `mixin`s and its methods:
## PanDetector


## Touch and mouse detectors
`PanDetector` is the last remaining detector mixin — the older style of input handling, added
directly to the game class instead of to a component. Everything else on that side has already been
replaced by the `Callbacks` mixins above.

```{warning}
Detectors will be deprecated in the future. Prefer `Callbacks` instead.
`PanDetector` will be removed. Prefer [`DragCallbacks`](drag_events.md), which
can be added to your `FlameGame` directly and additionally reports a
`pointerId` so that simultaneous drags can be told apart.
```

```text
Expand All @@ -33,14 +38,6 @@ Detectors will be deprecated in the future. Prefer `Callbacks` instead.
- onPanCancel
```

Mouse only events

```text
- MouseMovementDetector
- onMouseMove
```


Flame's GestureApi is provided by Flutter's Gesture Widgets, including
[GestureDetector widget](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html),
[RawGestureDetector widget](https://api.flutter.dev/flutter/widgets/RawGestureDetector-class.html)
Expand Down Expand Up @@ -147,22 +144,3 @@ class MyGame extends FlameGame with PanDetector {
}
}
```


### GestureHitboxes

The `GestureHitboxes` mixin is used to more accurately recognize gestures on top of your
`Component`s. Say that you have a fairly round rock as a `SpriteComponent` for example, then you
don't want to register input that is in the corner of the image where the rock is not displayed,
since a `PositionComponent` is rectangular by default. Then you can use the `GestureHitboxes` mixin
to define a more accurate circle or polygon (or another shape) for which the input should be within
for the event to be registered on your component.

You can add new hitboxes to the component that has the `GestureHitboxes` mixin just like they are
added in the below `Collidable` example.

More information about how to define hitboxes can be found in the hitbox section of the
[collision detection](../collision_detection.md#shapehitbox) docs.

An example of how to use it can be seen in the
[gesture hitboxes example](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/input/gesture_hitboxes_example.dart).
21 changes: 21 additions & 0 deletions doc/flame/inputs/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ works, but adapted for Flame's component tree.
- [Pointer Events](pointer_events.md)
- [Hardware Keyboard Detector](hardware_keyboard_detector.md)


## GestureHitboxes

Every mixin whose events carry a position implements `PointerInputCallbacks` — that is all of the
above except keyboard — and they all decide whether an event belongs to a component by asking its
`containsLocalPoint()`, which for a `PositionComponent` is its rectangular bounds. The
`GestureHitboxes` mixin is used to recognize input on top of your `Component`s more accurately than
that. Say that you have a fairly round rock as a `SpriteComponent` for example, then you don't want
to register input that is in the corner of the image where the rock is not displayed. Then you can
use the `GestureHitboxes` mixin to define a more accurate circle or polygon (or another shape) for
which the input should be within for the event to be registered on your component.

You can add new hitboxes to the component that has the `GestureHitboxes` mixin just like they are
added in the `Collidable` example.

More information about how to define hitboxes can be found in the hitbox section of the
[collision detection](../collision_detection.md#shapehitbox) docs.

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

```{toctree}
:hidden:

Expand Down
14 changes: 7 additions & 7 deletions doc/flame/inputs/pointer_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ which is still supported, is described in [](gesture_input.md).
**Pointer events** are Flutter's generalized "mouse-movement"-type events (for desktop or web).

If you want to interact with mouse movement events within your component or game, you can use the
`PointerMoveCallbacks` mixin.
`MouseMoveCallbacks` mixin.

For example:

```dart
class MyComponent extends PositionComponent with PointerMoveCallbacks {
class MyComponent extends PositionComponent with MouseMoveCallbacks {
MyComponent() : super(size: Vector2(80, 60));

@override
void onPointerMove(PointerMoveEvent event) {
void onMouseMove(MouseMoveEvent event) {
// Do something in response to the mouse move (e.g. update coordinates)
}
}
```

The mixin adds two overridable methods to your component:

- `onPointerMove`: called when the mouse moves within the component
- `onPointerMoveStop`: called once if the component was being hovered and the mouse leaves
- `onMouseMove`: called when the mouse moves within the component
- `onMouseMoveStop`: called once if the component was being hovered and the mouse leaves

By default, each of these methods does nothing, they need to be overridden in order to perform any
function.
Expand All @@ -36,7 +36,7 @@ In addition, the component must implement the `containsLocalPoint()` method (alr
Flame to know whether the event occurred within the component or not.

Note that only mouse events happening within your component will be proxied along. However,
`onPointerMoveStop` will be fired once on the first mouse movement that leaves your component, so
`onMouseMoveStop` will be fired once on the first mouse movement that leaves your component, so
you can handle any exit conditions there.


Expand Down Expand Up @@ -69,7 +69,7 @@ class MyComponent extends PositionComponent with HoverCallbacks {
}
```

Note that you can still listen to the "raw" onPointerMove methods for additional functionality, just
Note that you can still listen to the "raw" onMouseMove methods for additional functionality, just
make sure to call the `super` version to enable the `HoverCallbacks` behavior.


Expand Down
57 changes: 57 additions & 0 deletions doc/flame/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,63 @@ scrolls that occur on top of it, as determined by `containsLocalPoint()`. Mixing
See [Pointer Events](inputs/pointer_events.md) for the full replacement API.


### `MouseMovementDetector` removed and `PointerMove*` renamed to `MouseMove*`

The `MouseMovementDetector` game mixin has been removed, together with the event class that only it
used. At the same time, the component-level API it is replaced by has been renamed from `PointerMove`
to `MouseMove`:

| Removed / renamed | Use instead |
| --- | --- |
| `MouseMovementDetector` | `MouseMoveCallbacks` |
| `PointerHoverInfo` | `MouseMoveEvent` |
| `PointerMoveCallbacks` | `MouseMoveCallbacks` |
| `PointerMoveEvent` | `MouseMoveEvent` |
| `PointerMoveDispatcher` | `MouseMoveDispatcher` |
| `onPointerMove` | `onMouseMove` |
| `onPointerMoveStop` | `onMouseMoveStop` |

The rename has two reasons. Flame's `PointerMoveEvent` collided with Flutter's class of the same
name, forcing a `hide` on any file that imported both `package:flame/events.dart` and
`package:flutter/material.dart`. And "mouse move" is simply more accurate: the event wraps Flutter's
`PointerHoverEvent` and is delivered from a `MouseRegion`, so it is mouse movement specifically, not
pointer movement in general. `MouseMoveDispatcherKey` was already named this way.

Migrating from the detector, the callback keeps its `onMouseMove` name and only the parameter
changes, with the position read directly off the event instead of through the nested `eventPosition`
wrapper:

```dart
// Before
class MyGame extends FlameGame with MouseMovementDetector {
@override
void onMouseMove(PointerHoverInfo info) {
target = info.eventPosition.widget;
}
}

// After
class MyGame extends FlameGame with MouseMoveCallbacks {
@override
void onMouseMove(MouseMoveEvent event) {
target = event.canvasPosition;
}
}
```

Unlike the old detector, which received every mouse movement anywhere on the game surface,
`MouseMoveCallbacks` is routed by position like the other component callbacks: a component only
receives movements that occur on top of it, as determined by `containsLocalPoint()`. Mixing it into
your `FlameGame` subclass directly, as above, keeps the old whole-surface behavior.
`MouseMoveCallbacks` additionally offers `onMouseMoveStop`, which has no equivalent on the old
detector.

`flame_test`'s `createMouseMoveEvent` helper now returns a `MouseMoveEvent`, and if you were using
`flame_behaviors`, note that it no longer re-exports the legacy `*Info` event classes.

See [Pointer Events](inputs/pointer_events.md) for the full replacement API.


### `onDragCancel` no longer delegates to `onDragEnd`

`DragCallbacks.onDragCancel` used to convert the cancellation into an `onDragEnd` event by default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import 'package:examples/stories/bridge_libraries/flame_forge2d/utils/boundaries
import 'package:examples/stories/bridge_libraries/flame_forge2d/utils/style.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/input.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart' show Colors, Paint, Canvas;

class RaycastExample extends Forge2DExampleGame with MouseMovementDetector {
class RaycastExample extends Forge2DExampleGame with MouseMoveCallbacks {
static const String description = '''
This example shows how ray casts can be used to find the nearest and
farthest shapes.
Expand Down Expand Up @@ -57,22 +56,22 @@ class RaycastExample extends Forge2DExampleGame with MouseMovementDetector {
}

@override
void onMouseMove(PointerHoverInfo info) {
void onMouseMove(MouseMoveEvent event) {
final rayStart = screenToWorld(
Vector2(
camera.viewport.size.x / 4,
camera.viewport.size.y / 2,
),
);

final worldPosition = screenToWorld(info.eventPosition.widget);
final worldPosition = screenToWorld(event.canvasPosition);
final redRayTarget = worldPosition + Vector2(0, 2);
fireRedRay(rayStart, redRayTarget);

final blueRayTarget = worldPosition - Vector2(0, 2);
fireBlueRay(rayStart, blueRayTarget);

super.onMouseMove(info);
super.onMouseMove(event);
}

void fireBlueRay(Vector2 rayStart, Vector2 rayTarget) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flame/geometry.dart';
import 'package:flame/input.dart';
import 'package:flame/palette.dart';
import 'package:flutter/material.dart';

class RaycastLightExample extends FlameGame
with HasCollisionDetection, TapCallbacks, MouseMovementDetector {
with HasCollisionDetection, TapCallbacks, MouseMoveCallbacks {
static const description = '''
In this example the raycast functionality is showcased by using it as a light
source, if you move the mouse around the canvas the rays will be cast from its
Expand Down Expand Up @@ -95,8 +94,8 @@ with with mouse.
}

@override
void onMouseMove(PointerHoverInfo info) {
final origin = info.eventPosition.widget;
void onMouseMove(MouseMoveEvent event) {
final origin = event.canvasPosition;
isOriginCasted = origin == this.origin;
this.origin = origin;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:flame/palette.dart';
import 'package:flutter/material.dart';

class RaytraceExample extends FlameGame
with HasCollisionDetection, MouseMovementDetector, TapCallbacks {
with HasCollisionDetection, MouseMoveCallbacks, TapCallbacks {
static const description = '''
In this example the raytrace functionality is showcased.
Click to start sending out a ray which will bounce around to visualize how it
Expand Down Expand Up @@ -124,8 +124,8 @@ bounce on will appear.
}

@override
void onMouseMove(PointerHoverInfo info) {
final origin = info.eventPosition.widget;
void onMouseMove(MouseMoveEvent event) {
final origin = event.canvasPosition;
isOriginCasted = origin == this.origin;
this.origin = origin;
}
Expand Down
7 changes: 3 additions & 4 deletions examples/lib/stories/input/mouse_cursor_example.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import 'package:flame/events.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame/palette.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class MouseCursorExample extends FlameGame with MouseMovementDetector {
class MouseCursorExample extends FlameGame with MouseMoveCallbacks {
static const String description = '''
Example showcasing the ability to change the game cursor in runtime
hover the little square to see the cursor changing
Expand All @@ -23,8 +22,8 @@ class MouseCursorExample extends FlameGame with MouseMovementDetector {
bool onTarget = false;

@override
void onMouseMove(PointerHoverInfo info) {
target = info.eventPosition.widget;
void onMouseMove(MouseMoveEvent event) {
target = event.canvasPosition;
}

Rect _toRect() => position.toPositionedRect(objSize);
Expand Down
9 changes: 4 additions & 5 deletions examples/lib/stories/input/mouse_movement_example.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import 'package:flame/events.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame/palette.dart';
import 'package:flutter/material.dart';

class MouseMovementExample extends FlameGame with MouseMovementDetector {
class MouseMovementExample extends FlameGame with MouseMoveCallbacks {
static const String description = '''
In this example we show how you can use `MouseMovementDetector`.\n\n
In this example we show how you can use `MouseMoveCallbacks`.\n\n
Move around the mouse on the canvas and the white square will follow it and
turn into blue if it reaches the mouse, or the edge of the canvas.
''';
Expand All @@ -23,8 +22,8 @@ class MouseMovementExample extends FlameGame with MouseMovementDetector {
bool onTarget = false;

@override
void onMouseMove(PointerHoverInfo info) {
target = info.eventPosition.widget;
void onMouseMove(MouseMoveEvent event) {
target = event.canvasPosition;
}

Rect _toRect() => position.toPositionedRect(objSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame/sprite.dart';

class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
class IsometricTileMapExample extends FlameGame with MouseMoveCallbacks {
static const String description = '''
Shows an example of how to use the `IsometricTileMapComponent`.\n\n
Move the mouse over the board to see a selector appearing on the tiles.
Expand Down Expand Up @@ -72,8 +71,8 @@ class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
}

@override
void onMouseMove(PointerHoverInfo info) {
final screenPosition = info.eventPosition.widget;
void onMouseMove(MouseMoveEvent event) {
final screenPosition = event.canvasPosition;
final block = base.getBlock(screenPosition);
selector.show = base.containsBlock(block);
selector.position.setFrom(topLeft + base.getBlockRenderPosition(block));
Expand Down
Loading
Loading