- Fix render-context cleanup in `Component.renderChild` to use the child's original context length
- Accumulators key by `Image` (instead of identity hash)
- Allow `ShapeHitbox` children to render hitbox debug visuals when needed
- Add stricter eligibility checks (decorator constraints, and excluding non-srcOver blend modes)
- Minor test string updates and removal of an unused import in the example.
`raytrace()` reuses the same `RaycastResult` objects across bounces, so
the reflected direction from one bounce becomes the incident direction
for the next. `Vector2.reflect()` is not bit-exact, so each bounce
introduces a tiny floating-point rounding error. After enough bounces
the direction's length drifts just past the `1e-6` tolerance that `Ray2`
enforces, causing a `direction must be normalized` assertion crash.
Two fixes:
- **`CircleHitbox`** and **`PolygonRayIntersection`** (used by
`RectangleHitbox` / `PolygonHitbox`): call `normalize()` on the
reflected direction before passing it to `Ray2`, so drift is corrected
on every bounce.
- **`raytrace_example`**: the initial ray direction was set via a
cascade on the `Vector2` getter (`ray.direction..setValues(...)`), which
bypasses the `direction=` setter and leaves the cached inverse values
stale. Fixed to assign through the setter.
Regression tests are included that inject a direction whose length² is
already above the threshold (by writing directly to the underlying
`Vector2`, bypassing the setter), then assert that `raycast()` does not
throw.
---------
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
This PR introduces object pooling functionality to Flame through the new
`ComponentPool` class. Object pooling is a performance optimization
technique that reduces garbage collection pressure by reusing component
instances instead of creating and destroying them repeatedly.
ComponentPool is a generic pool that works with any `Component`. Manages
reusable components with configurable sizing, automatic lifecycle
handling, and LIFO reuse order. Components are automatically returned to
the pool when removed from the game tree via `removeFromParent()`.
Bump the Flutter and dartdoc version so that we can develop with the new
Flutter version.
This aggressive bump is due to Flutter bumping dartdoc to 9.0.0.
Currently, scaling is only working on device scale. This PR allows
scaling gesture to be applied on components, very much like dragging
works with drag callbacks. I added a ScaleDispatcher component which
works very similarly to MultiDragDispatcher, basically sending the
callbacks of ScaleGestureRecognizer to the components.
There was some tricky parts though. The goal was to preserve multi drag
functionality while adding scale functionality but I run into this issue
:
When running concurrently ScaleGestureRecognizer and
ImmediateMultiDragGestureRecognizer, since drag in a simpler gesture it
is usually recognized before scale, and therefore, drag wins the gesture
arena and one pointer (finger) gets reserved for dragging. Scale gets
recognized a bit later, but with a single pointer, and data such as
scale or rotation are meaningless with a single pointer.
More generally, multi dragging and scaling are two very similar gestures
and it will inevitably lead to some ambiguities.
There was multiple solutions to this, all with their own drawbacks :
1. Not allowing multi dragging and scaling at the same time, with a
mechanic to switch between the two. Simple to implement
but quite limiting.
2. Introducing a delay with DelayedMultiDragGestureRecognizer, the
simplest solution, works well since scaling then gets recognized before
dragging, removing the ambiguity. The default delay is unacceptably long
though but I did not experiment with shorter delay.
3. Using the data from the dragging pointer, to reconstruct rotation and
scaling data, as if the dragging pointer was part of the scaling
gesture.
We decided to go with the third solution as it preserves the ability to
do multi drag instantaneously while allowing scaling at the same time.
One issue inherent to this solution is also linked to the ambiguity
between some multi drag gestures and scaling, preventing some multi drag
gestures to be performed properly (basically all multi drag gestures
similar to scaling).
One possibility would be to use the data from the single pointer scaling
and send that to MultiDragDispatcher, basically what solution 3 does but
the other way around. this would allow for drag and scaling to work at
the same time.
Another issue exists that might be fixable though : it doesn't behave
great when three fingers are involved, basically when I lift one of the
two first fingers, the third one is used in the scale and rotation
computations leading to unwanted "jumps".
The issue is that pointers are not really tracked, so eventually the
third finger position can be used as if it was the second one.
## Future things to do after this PR
- fix the 3 finger issues described above
- add a simple switch mechanism to activate/deactivate scale gesture
recognizing at run time to allow for full real multi drag to work OR
investigate "use the data from the single pointer scaling" solution.
---------
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
Co-authored-by: Lukas Klingsbo <lukas.klingsbo@gmail.com>
Modifies LinearLayoutComponent such that when oriented vertically and
set to CrossAxisAlignment.stretch, whenever it encounters a child that
is a TextBoxComponent, sets its `boxConfig.maxWidth` to the appropriate
width.
Currently dependent on https://github.com/flame-engine/flame/pull/3777,
so that has to be merged first before this.
This is only a minor breaking change. If you were using a
TextBoxComponent inside LinearLayoutComponent, chances are you had to do
weird things to make it work as you expect. You'd simply have to remove
the workaround code you wrote for it.
---------
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
Currently, when `boxConfig.maxWidth` is changed, TextBoxComponent does
not reflow its text. This PR fixes this.
Note that this PR includes a non-standard control in its example. This
is intentional because the point of this PR is to support the change to
an existing instantiated component. Using a standard Dashbook control
obviates the point of this PR. Once
https://github.com/bluefireteam/dashbook/issues/128 is done, this will
be migrated.
---------
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
As-is, the existing `flame_spine` supports Spine 4.2. `spine_flutter` in
4.3.0 now supports Spine 4.3, and this is backwards incompatible and
breaking. If you need Spine 4.2, you should not upgrade to `flame_spine`
0.3.0, but this is for anyone who is ready to make the Spine 4.3 jump.
We recommend pinning to 0.2.2 for `spine_flutter` 4.2.36 if you are
staying on Spine 4.2.
The top-level API has many breaking changes, and this changelog has a
good summary of what needs to be done:
https://pub.dev/packages/spine_flutter/changelog
The Dart code changes are relatively straightforward, but any Spine
models need to be re-exported through the 4.3 Spine Editor (and you
SHOULD make sure that all models still do everything that is expected!
There might be random bones that don't look right any more, random
animations, and certain models just don't work.)
Dart API changes: https://pub.dev/packages/spine_flutter/changelog
Re-export at 4.2 Spine models from the 4.3 Spine Editor and confirm each
model works.
Implements an `ExpandedComponent`, which takes up as much space as
possible along the main axis within a `LinearLayoutComponent`. With more
than one `ExpandedComponent`, this expansion is divided equally.
`PaddingComponent` now inherits from `SingleLayoutComponent`.
---------
Co-authored-by: Lukas Klingsbo <lukas.klingsbo@gmail.com>
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
Support secondary taps (right click) on new callbacks system.
In order to follow through with our [event system
migration](https://docs.google.com/document/d/1nBUup9QCPioVwWL1zs79z1hWF882tAYfNywFMdye2Qc),
we need to make sure the new system is equipped to support all use
cases; also changes the existing TapCallbacks to be primary-only.
I noticed that we don't support "secondary taps" (i.e. right clicks), so
I am adding this. I honestly really dislike the fact that this is
considered a completely different event from the left click, instead of
just a property on the click event. But I kept this structure to
replicate what Flutter does, so this is more familiar for users. I think
that is worth the slight verbosity of having yet another detector. Also,
it plays well this way with Flutter because that underlying events are a
bit different (for example, the secondary ones don't support `pointId`).
Note: this is a slight breaking change because the existing detector
works for BOTH left and right click, but there is NO WAY of
distinguishing them because the `buttons` property is not propagated in
the Flutter end (massive oversight I believe - might put a PR later).
Since this provides the secondary as a solution, it also removes
secondary clicks from triggering the primary. I think this is more
versatile than having tap detector=`(primary OR secondary)` and
secondary=`(secondary only)`.
I don't think this should affect basically any users because (1) desktop
only and (2) this acceptance of right clicks was probably a bug anyway
(for example, on the example it would rotate the square and also open
the context menu, which is jarring).
However I am happy to add an option or pursue a different approach, I
believe this is the best path forward, IMO.
Remove all `.metadata` files across the monorepo and add them to
.gitignore.
They just serve to cause conflicts whenever someone runs anything and
according to @wolfenrain "we don't need them".
Since the `FixedResolutionViewport` reports the canvas size as size we
have to use the `virtualSize` when fullscreening the `ParallaxComponent`
within such viewport.
Removes the `shrinkWrap` property from `LayoutComponent` and its
subclasses, and make the `size` setter nullable. Setting the `size` to
null causes the `LayoutComponent` to behave as if it were
`shrinkWrap`ed.
---------
Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
```
Package Name Current Version Updated Version Update Reason
flame 1.29.0 2.0.0 updated with major changes
flame_sprite_fusion 0.1.3+12 0.2.0 updated with major changes
flame_svg 1.11.12 1.11.13 updated with patch changes
flame_test 1.19.2 2.0.0 updated with major changes
flame_texturepacker 4.3.1 4.4.0 updated with minor changes
flame_tiled 3.0.3 3.0.4 updated with patch changes
flame_behavior_tree 0.1.3+12 0.1.3+13 dependency was updated
flame_oxygen 0.2.3+12 0.2.3+13 dependency was updated
flame_isolate 0.6.2+12 0.6.2+13 dependency was updated
flame_fire_atlas 1.8.7 1.8.8 dependency was updated
flame_audio 2.11.6 2.11.7 dependency was updated
flame_spine 0.2.2+12 0.2.2+13 dependency was updated
flame_bloc 1.12.13 1.12.14 dependency was updated
flame_kenney_xml 0.1.1+12 0.1.1+13 dependency was updated
flame_lottie 0.4.2+12 0.4.2+13 dependency was updated
flame_markdown 0.2.4+5 0.2.4+6 dependency was updated
flame_console 0.1.2+8 0.1.2+9 dependency was updated
flame_rive 1.10.15 1.10.16 dependency was updated
flame_forge2d 0.19.0+2 0.19.0+3 dependency was updated
flame_noise 0.3.2+12 0.3.2+13 dependency was updated
flame_riverpod 5.4.15 5.4.16 dependency was updated
flame_network_assets 0.3.3+12 0.3.3+13 dependency was updated
flame_3d 0.1.0-dev.12 0.1.0-dev.13 dependency was updated
```
Due to a race (I'm guessing) sometimes the crystal ball game will try to
access the game after it has been changed to another example, thus
making the examples app crash since the crystal ball game has the
`SingleGameInstance` mixin on the game.
Closes#3597