Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This creates HoverCallbacks (and PointerMoveCallbacks) to replicate the Hoverables behaviour in the new camera and event system.
- Loading branch information
1 parent
83f5ea4
commit d460b84
Showing
18 changed files
with
624 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,3 +156,4 @@ viewports | |
vsync | ||
widget's | ||
unawaited | ||
proxied |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import 'dart:math'; | ||
|
||
import 'package:flame/components.dart'; | ||
import 'package:flame/events.dart'; | ||
import 'package:flame/game.dart'; | ||
import 'package:flutter/rendering.dart'; | ||
|
||
class PointerEventsGame extends FlameGame with TapCallbacks { | ||
@override | ||
Future<void> onLoad() async { | ||
add(HoverTarget(Vector2(100, 200))); | ||
add(HoverTarget(Vector2(300, 300))); | ||
add(HoverTarget(Vector2(400, 50))); | ||
} | ||
|
||
@override | ||
void onTapDown(TapDownEvent event) { | ||
add(HoverTarget(event.localPosition)); | ||
} | ||
} | ||
|
||
class HoverTarget extends PositionComponent with HoverCallbacks { | ||
static final Random _random = Random(); | ||
|
||
HoverTarget(Vector2 position) | ||
: super( | ||
position: position, | ||
size: Vector2.all(50), | ||
anchor: Anchor.center, | ||
); | ||
|
||
final _paint = Paint() | ||
..color = HSLColor.fromAHSL(1, _random.nextDouble() * 360, 1, 0.8) | ||
.toColor() | ||
.withOpacity(0.5); | ||
|
||
@override | ||
void render(Canvas canvas) { | ||
canvas.drawRect(size.toRect(), _paint); | ||
} | ||
|
||
@override | ||
void onHoverEnter() { | ||
_paint.color = _paint.color.withOpacity(1); | ||
} | ||
|
||
@override | ||
void onHoverExit() { | ||
_paint.color = _paint.color.withOpacity(0.5); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Pointer Events | ||
|
||
```{note} | ||
This document describes the new events API. The old (legacy) approach, | ||
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. | ||
|
||
For example: | ||
|
||
```dart | ||
class MyComponent extends PositionComponent with PointerMoveCallbacks { | ||
MyComponent() : super(size: Vector2(80, 60)); | ||
@override | ||
void onPointerMove(PointerMoveEvent 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 | ||
|
||
By default, each of these methods does nothing, they need to be overridden in order to perform any | ||
function. | ||
|
||
In addition, the component must implement the `containsLocalPoint()` method (already implemented in | ||
`PositionComponent`, so most of the time you don't need to do anything here) -- this method allows | ||
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 | ||
you can handle any exit conditions there. | ||
|
||
|
||
## HoverCallbacks | ||
|
||
If you want to specifically know if your component is being hovered or not, or if you want to hook | ||
into hover enter and exist events, you can use a more dedicated mixin called `HoverCallbacks`. | ||
|
||
For example: | ||
|
||
```dart | ||
class MyComponent extends PositionComponent with HoverCallbacks { | ||
MyComponent() : super(size: Vector2(80, 60)); | ||
@override | ||
void update(double dt) { | ||
// use `isHovered` to know if the component is being hovered | ||
} | ||
@override | ||
void onHoverEnter() { | ||
// Do something in response to the mouse entering the component | ||
} | ||
@override | ||
void onHoverExit() { | ||
// Do something in response to the mouse leaving the component | ||
} | ||
} | ||
``` | ||
|
||
Note that you can still listen to the "raw" onPointerMove methods for additional functionality, just | ||
make sure to call the `super` version to enable the `HoverCallbacks` behavior. | ||
|
||
|
||
### Demo | ||
|
||
Play with the demo below to see the pointer hover events in action. | ||
|
||
```{flutter-app} | ||
:sources: ../flame/examples | ||
:page: pointer_events | ||
:show: widget code | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 14 additions & 14 deletions
28
...lib/stories/input/hoverables_example.dart → ...tories/input/hover_callbacks_example.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
packages/flame/lib/src/events/component_mixins/hover_callbacks.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import 'package:flame/events.dart'; | ||
import 'package:flame/src/components/core/component.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
/// This mixin can be added to a [Component] allowing it to receive hover | ||
/// events. | ||
/// | ||
/// In addition to adding this mixin, the component must also implement the | ||
/// [containsLocalPoint] method -- the component will only be considered | ||
/// "hovered" if the point where the hover event occurred is inside the | ||
/// component. | ||
/// | ||
/// This mixin is the replacement of the Hoverable mixin. | ||
mixin HoverCallbacks on Component implements PointerMoveCallbacks { | ||
bool _isHovered = false; | ||
|
||
/// Returns true while the component is being dragged. | ||
bool get isHovered => _isHovered; | ||
|
||
void onHoverEnter() {} | ||
|
||
void onHoverExit() {} | ||
|
||
void _doHoverEnter() { | ||
_isHovered = true; | ||
onHoverEnter(); | ||
} | ||
|
||
void _doHoverExit() { | ||
_isHovered = false; | ||
onHoverExit(); | ||
} | ||
|
||
@override | ||
void onPointerMove(PointerMoveEvent event) { | ||
final position = event.localPosition; | ||
if (containsLocalPoint(position)) { | ||
if (!_isHovered) { | ||
_doHoverEnter(); | ||
} | ||
} else { | ||
if (_isHovered) { | ||
_doHoverExit(); | ||
} | ||
} | ||
} | ||
|
||
@override | ||
void onPointerMoveStop(PointerMoveEvent event) { | ||
if (_isHovered) { | ||
_doHoverExit(); | ||
} | ||
} | ||
|
||
@override | ||
@mustCallSuper | ||
void onMount() { | ||
super.onMount(); | ||
PointerMoveCallbacks.onMountHandler(this); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
packages/flame/lib/src/events/component_mixins/pointer_move_callbacks.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import 'package:flame/events.dart'; | ||
import 'package:flame/src/components/core/component.dart'; | ||
import 'package:flame/src/events/flame_game_mixins/pointer_move_dispatcher.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
/// This mixin can be added to a [Component] allowing it to receive | ||
/// pointer movement events. | ||
mixin PointerMoveCallbacks on Component { | ||
void onPointerMove(PointerMoveEvent event) {} | ||
|
||
void onPointerMoveStop(PointerMoveEvent event) {} | ||
|
||
@override | ||
@mustCallSuper | ||
void onMount() { | ||
super.onMount(); | ||
onMountHandler(this); | ||
} | ||
|
||
static void onMountHandler(PointerMoveCallbacks instance) { | ||
final game = instance.findGame()!; | ||
const key = MouseMoveDispatcherKey(); | ||
if (game.findByKey(key) == null) { | ||
final dispatcher = PointerMoveDispatcher(); | ||
game.registerKey(key, dispatcher); | ||
game.add(dispatcher); | ||
} | ||
} | ||
} |
Oops, something went wrong.