Skip to content

Conversation

@stilnat
Copy link
Contributor

@stilnat stilnat commented Nov 24, 2025

Description

Currently flame handle scale input events in a very hacky way, by getting the drag gesture recognizer data and recomputing
the data for the scale gesture. This has multiple issues :

  • Recompute already computed stuff like rotation and scale factor -> inefficient
  • Make the code difficult to understand, had to introduce hard dependencies between scale and drag dispatcher
  • Limits the allowed multi drag gestures : those looking like scale gestures simply would not register as such but only as scale

This PR aims to fix all those issues by introducing a new gesture recognizer, which is basically just a mix of ScaleGestureRecognizer and immediateMultiDragGestureRecognizer, allowing pointers to be used for both gestures
without competing. I used the existing flutter code to write it.

I modified a bit ScaleCallbacks and DragCallbacks, so they use their original dispatcher if there is only one type
of them (it's a bit more efficient), and so they upgrade to using MultiDragScaleDispatcher if both mixins are mounted.
Transition between the two is smooth as the old dispatcher wait for all gestures it started to finish before removing itself.

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples or docs.

I wonder if gesture_input.md should be updated

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Related Issues

I believe it Closes #2635

@stilnat stilnat changed the title feat: Update scale event with custom recogniser feat: Update scale event with custom recognizer Nov 25, 2025
Copy link
Member

@spydon spydon left a comment

Choose a reason for hiding this comment

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

Looks good, just a few comments

Comment on lines +2 to +5
import 'package:flame/components.dart' hide Matrix4;
import 'package:flame/events.dart' hide PointerMoveEvent;
import 'package:flame/game.dart' hide Matrix4;
import 'package:flutter/material.dart' hide PointerMoveEvent, Matrix4;
Copy link
Member

Choose a reason for hiding this comment

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

Are these hides really necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

might be leftover I'll check

bool _tryRemoving() {
// there's no more fingers
// that started dragging before _shouldBeRemoved flag was set to true.
if (_records.isEmpty && _shouldBeRemoved && isMounted) {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't it remove it directly even if there are fingers still left on the screen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so the thought behind this is that removing immediately the recognizer would abruptly end currently performed gestures which sounds like unwanted behavior to me (but let me know if that's acceptable).

I didn't check if removing immediately would do that though but I wrote a test for that so I can try and run the test if I just call removeFromParent immediately instead.

Copy link
Member

Choose a reason for hiding this comment

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

I think it should send out a cancel event for the gesture when this happens.
Imagine a game where you are steering the player using some drag inputs and then you want to add a cut scene or something, so you remove the input capabilities, then if the gestures aren't ended directly the user can still move the player until they release the gesture.

bool _tryRemoving() {
// there's no more fingers
// that started dragging before _shouldBeRemoved flag was set to true.
if (_records.isEmpty && _shouldBeRemoved && isMounted) {
Copy link
Member

Choose a reason for hiding this comment

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

Same here, I don't think markForRemoval should exist, we should just call removeFromParent and then do clean-up in onRemove.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same comment as above

Co-authored-by: Lukas Klingsbo <lukas.klingsbo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ScaleDetector doesn't work when a Component with DragCallbacks is added

2 participants