This adds `DisplacementEvent` to fix delta coordinate transformations
for drag events, to be used instead of `PositionEvent`.
Drag Events now expose the start and end position, as well as the delta,
correctly transformed by the camera and zoom.
This also ensures that drag events, once starts, do not get lost if the
drag update leaves the component bounds.
* if you are using `DragUpdateEvent` events, the `devicePosition`,
`canvasPosition`, `localPosition`, and `delta` are deprecated as they
are unclear.
* use `xStartPosition` to get the position at the start of the drag
event ("from")
* use `xEndPosition` to get the position at the end of the drag event
("to")
* if you want the delta, use `localDelta`. it now already considers the
camera zoom. no need to manually account for that
* now you keep receiving drag events for the same component even if the
mouse leaves the component (breaking)
---------
Co-authored-by: Lukas Klingsbo <lukas.klingsbo@gmail.com>
Primarily this PR is completing Step 5 of Flame's Klondike Tutorial and removing the tbc.md file ("To be continued...").
As at the end of Step 4, the Klondike Game had no animation, other than the drag-and-drop moves to play the game. It also had no ways to detect a win, react to a win or play again without re-loading and re-running the whole app. Step 4 played the Klondike Draw 3 variation of Klondike. Step 5 introduces the easier Klondike Draw 1 variation and provides buttons to:
Choose between Draw 1 and Draw 3,
Start the game again with a new deal, or
Start again with the same deal as before.
The new code and step5.md tutorial text cover Effects and EffectControllers in some detail, with complex examples of their use. The animations include:
Returning dropped but misplaced cards to the places they came from,
Settling dropped and validly placed cards into position,
Flipping cards from Stock Pile to Waste Pile,
Turning cards over on the Tableau piles when the cards above them are moved away,
Collecting multiple cards when the game is over,
Dealing and re-dealing multiple cards,
Allowing a card to be auto-moved onTapUp() to its Foundation Pile if it is ready to go out,
Providing a display of moving cards when/if the player wins.
Firstly, (re Issue #2799) Flame 1.9.x broke the Klondike Tutorial, which was not set up to use the new built-in world and camera. So I modified the KlondikeGame's onLoad() code to use the built-in world and camera and no longer create its own World and CameraComponent. I also updated the step2.md documentation file, which instructs new users of Flame on how to use the world and the camera, how to set up a game-oriented co-ordinate system and how to fit it into the device screen.
Secondly, (re Issue #2798) Klondike was not adhering to the design stated in the Tutorial, that all 52 Card objects would be owned by the KlondikeGame. During the shuffle and deal sequence it was using removeLast() on the List\<Card\>cards, where the cards are kept, the result being that only 24 of the 52 cards were left in the list after the deal. I have fixed the bug and updated the Tutorial documentation (step4) which discusses how the deal is coded.
This bug does not affect the gameplay as it stands, but it does block the way to future features at the game level, such as an option to re-deal or a win-animation where all cards fly off the screen.
It doesn't make any sense for HasGameReference to have Game as a base instead of FlameGame since the mixin is on Component and clearly in a component tree context, so this PR sets the base to be FlameGame (like HasGameRef).
This PR adds the following lint rules to our list:
```
always_put_required_named_parameters_first
avoid_multiple_declarations_per_line
avoid_positional_boolean_parameters
avoid_returning_null_for_void
avoid_returning_this
avoid_unnecessary_containers
enable_null_safety
library_private_types_in_public_api
no_leading_underscores_for_library_prefixes
no_leading_underscores_for_local_identifiers
prefer_null_aware_method_calls
tighten_type_of_initializing_formals
unnecessary_late
use_setters_to_change_properties
```
And these rules were considered, and some changes were made according to
them as a clean-up, but in many places they didn't make sense
(`prefer_asserts_with_message` I would have included, but there were too
many places that needed to be changes):
```
collection_methods_unrelated_type
prefer_asserts_with_message
avoid_renaming_method_parameters
```
This PR is the second in a series of refactors that aim to simplify event handling in Flame. The approach is as follows:
Added the MultiTapDispatcher component, which contains the logic that used to be within the HasTappableComponents mixin. This component is internal; it mounts to a FlameGame directly, and ensures that it is a singleton.
Whenever any TapCallbacks component is added to a game, it automatically adds the MultiTapDispatcher component (unless there is already one), which in turn registers a tap gesture detector with GestureDetectorBuilder and rebuilds the game widget.
The end result is that now in order to make a component tappable you only need to add the TapCallbacks mixin to that component, everything else will be handled by the framework.
Consequently, the HasTappableComponents mixin is now empty and marked as deprecated.
This PR is first in a series of refactors that aim to simplify event handling in Flame. The approach is as follows:
Added class GestureDetectorBuilder, which encapsulates the logic of applyGestureDetectors() in a class. This class resides within the Game and initiates widget rebuild whenever any new gesture detectors are added or removed. Note:
[idea] Convert HasTappableComponents/HasDraggableComponents into classes #1733 suggests having a list of interfaces inside the Game class -- this is essentially that list, encapsulated in a class.
Added the MultiDragDispatcher component, which contains the logic that used to be within the HasDraggableComponents mixin. This component is internal; it mounts to a FlameGame directly, and ensures that it is a singleton.
Whenever any DragCallbacks component is added to a game, it automatically adds the MultiDragDispatcher component (unless there is already one), which in turn registers a drag gesture detector with GestureDetectorBuilder and rebuilds the game widget.
The end result is that now in order to make a component draggable you only need to add the DragCallbacks mixin to that component, everything else will be handled by the framework.
Consequently, the HasDraggableComponents mixin is now empty and marked as deprecated.