aevyrie / bevy_mod_picking

Picking and pointer events for Bevy.
https://crates.io/crates/bevy_mod_picking
Apache License 2.0
764 stars 170 forks source link

Drag and DragEnd system ordering inconsistencies #294

Open Vrixyz opened 8 months ago

Vrixyz commented 8 months ago

Context

I want to implement a drag and drop, when dropping, I want to "snap" the position.

bug description

Sometimes, the snapping occurs incorrectly. this bug doesn't happen on all sessions, but is easily reproducible after a few relaunches.

DragEnd event sometimes occurs before Drag events: so logic in DragEnd gets overridden by logic in Drag.

Video description

https://github.com/aevyrie/bevy_mod_picking/assets/2290685/5302bd08-95a4-407b-83e6-e90f8ee3ae38

More details

part of relevant code

```rs fn round_to_nearest(value: f32) -> f32 { (value / multiple).round() * 50f32 } ... // handle drag On::>::listener_component_mut::(|drag, transform| { transform.translation.x += drag.delta.x; transform.translation.y -= drag.delta.y; }), On::>::run(|event: ListenerMut>, mut transforms: Query<&mut Transform>,| { let Ok(mut transform) = transforms.get_mut(event.listener()) else { return; }; // snap to position transform.translation.x = round_to_nearest(transform.translation.x, 60f32); // Make the square follow the mouse transform.translation.y = round_to_nearest(transform.translation.y, 60f32); // re-enable picking commands.entity(event.target()).insert(Pickable::default()); }) ```

Trace image

Not sure why there are 2 drag events on the same frame too 🤔 ![image](https://github.com/aevyrie/bevy_mod_picking/assets/2290685/c4e84edf-b25c-4a19-9141-bf02386d421c)

full tracy trace file: drag_trace.zip

Code source:https://github.com/Vrixyz/rsword/blob/8fbe5713856d971dc2e71eaad4ac200085314dfb/src/game.rs#L121

Thoughts on fix

I looked a tiny bit into how we could fix that, and I guess we could avoid sending a Drag when we detect a DragEnd ? Around https://github.com/Vrixyz/bevy_mod_picking/blob/1471a9f83435f3fdd43829b90391e6ab965e0e73/crates/bevy_picking_core/src/events.rs#L417-L418

Workaround

As a workaround, in user code I fire an event when a DragEnd is detected, so its logic is computed after last Drag inputs.

Code Screenshot

Screenshot 2024-01-01 at 21 33 39

aevyrie commented 6 months ago

This is caused by bevy's lack of inter-frame event ordering. There is no way to know if a mouse up came before or after a mouse move, or a mouse down before or after a mouse move within the same frame. Additionally, all the events are split into independent events. Once the bevy issue is fixed, the plugin will also need to switch to a unified pointer event stream.