bevy_mod_picking icon indicating copy to clipboard operation
bevy_mod_picking copied to clipboard

Drag and DragEnd system ordering inconsistencies

Open ThierryBerger opened this issue 2 years ago • 1 comments

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

fn round_to_nearest(value: f32) -> f32 {
    (value / multiple).round() * 50f32
}
...
// handle drag
On::<Pointer<Drag>>::listener_component_mut::<Transform>(|drag, transform| {
    transform.translation.x += drag.delta.x;
    transform.translation.y -= drag.delta.y;
}),
On::<Pointer<DragEnd>>::run(|event: ListenerMut<Pointer<DragEnd>>,
      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

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

ThierryBerger avatar Dec 29 '23 17:12 ThierryBerger

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.

aevyrie avatar Mar 03 '24 09:03 aevyrie