mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Emit picking event streams (#16105)
# Objective In `bevy_mod_picking` events are accessible through event listeners or `EventReader`s. When I replaced event listeners with observers, I removed the `EventReader` for simplicity. This adds it back. ## Solution All picking events are now properly registered, and can be accessed through `EventReader<Pointer<E>>`. `Pointer` now tracks the entity the event targeted initially, and this can also be helpful in observers (which don't currently do this). ## Testing The picking examples run fine. This shouldn't really change anything. --------- Co-authored-by: Aevyrie <aevyrie@gmail.com>
This commit is contained in:
parent
54b323ec80
commit
7451900e71
2 changed files with 166 additions and 112 deletions
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::{prelude::*, system::SystemParam};
|
||||||
use bevy_hierarchy::Parent;
|
use bevy_hierarchy::Parent;
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
|
@ -60,6 +60,8 @@ use crate::{
|
||||||
#[derive(Clone, PartialEq, Debug, Reflect, Component)]
|
#[derive(Clone, PartialEq, Debug, Reflect, Component)]
|
||||||
#[reflect(Component, Debug)]
|
#[reflect(Component, Debug)]
|
||||||
pub struct Pointer<E: Debug + Clone + Reflect> {
|
pub struct Pointer<E: Debug + Clone + Reflect> {
|
||||||
|
/// The original target of this picking event, before bubbling
|
||||||
|
pub target: Entity,
|
||||||
/// The pointer that triggered this event
|
/// The pointer that triggered this event
|
||||||
pub pointer_id: PointerId,
|
pub pointer_id: PointerId,
|
||||||
/// The location of the pointer during this event
|
/// The location of the pointer during this event
|
||||||
|
@ -97,8 +99,9 @@ impl<E: Debug + Clone + Reflect> core::ops::Deref for Pointer<E> {
|
||||||
|
|
||||||
impl<E: Debug + Clone + Reflect> Pointer<E> {
|
impl<E: Debug + Clone + Reflect> Pointer<E> {
|
||||||
/// Construct a new `Pointer<E>` event.
|
/// Construct a new `Pointer<E>` event.
|
||||||
pub fn new(id: PointerId, location: Location, event: E) -> Self {
|
pub fn new(target: Entity, id: PointerId, location: Location, event: E) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
target,
|
||||||
pointer_id: id,
|
pointer_id: id,
|
||||||
pointer_location: location,
|
pointer_location: location,
|
||||||
event,
|
event,
|
||||||
|
@ -260,6 +263,25 @@ pub struct PointerState {
|
||||||
pub dragging_over: HashMap<Entity, HitData>,
|
pub dragging_over: HashMap<Entity, HitData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper system param for accessing the picking event writers.
|
||||||
|
#[derive(SystemParam)]
|
||||||
|
pub struct PickingEventWriters<'w> {
|
||||||
|
cancel_events: EventWriter<'w, Pointer<Cancel>>,
|
||||||
|
click_events: EventWriter<'w, Pointer<Click>>,
|
||||||
|
down_events: EventWriter<'w, Pointer<Down>>,
|
||||||
|
drag_drop_events: EventWriter<'w, Pointer<DragDrop>>,
|
||||||
|
drag_end_events: EventWriter<'w, Pointer<DragEnd>>,
|
||||||
|
drag_enter_events: EventWriter<'w, Pointer<DragEnter>>,
|
||||||
|
drag_events: EventWriter<'w, Pointer<Drag>>,
|
||||||
|
drag_leave_events: EventWriter<'w, Pointer<DragLeave>>,
|
||||||
|
drag_over_events: EventWriter<'w, Pointer<DragOver>>,
|
||||||
|
drag_start_events: EventWriter<'w, Pointer<DragStart>>,
|
||||||
|
move_events: EventWriter<'w, Pointer<Move>>,
|
||||||
|
out_events: EventWriter<'w, Pointer<Out>>,
|
||||||
|
over_events: EventWriter<'w, Pointer<Over>>,
|
||||||
|
up_events: EventWriter<'w, Pointer<Up>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Dispatches interaction events to the target entities.
|
/// Dispatches interaction events to the target entities.
|
||||||
///
|
///
|
||||||
/// Within a single frame, events are dispatched in the following order:
|
/// Within a single frame, events are dispatched in the following order:
|
||||||
|
@ -298,6 +320,7 @@ pub fn pointer_events(
|
||||||
mut pointer_state: Local<HashMap<(PointerId, PointerButton), PointerState>>,
|
mut pointer_state: Local<HashMap<(PointerId, PointerButton), PointerState>>,
|
||||||
// Output
|
// Output
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
mut event_writers: PickingEventWriters,
|
||||||
) {
|
) {
|
||||||
// Setup utilities
|
// Setup utilities
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
@ -337,26 +360,30 @@ pub fn pointer_events(
|
||||||
.filter(|&&drag_target| hovered_entity != drag_target)
|
.filter(|&&drag_target| hovered_entity != drag_target)
|
||||||
{
|
{
|
||||||
state.dragging_over.insert(hovered_entity, hit.clone());
|
state.dragging_over.insert(hovered_entity, hit.clone());
|
||||||
commands.trigger_targets(
|
let drag_enter_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragEnter {
|
|
||||||
button,
|
|
||||||
dragged: *drag_target,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragEnter {
|
||||||
|
button,
|
||||||
|
dragged: *drag_target,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_enter_event.clone(), hovered_entity);
|
||||||
|
event_writers.drag_enter_events.send(drag_enter_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always send Over events
|
// Always send Over events
|
||||||
commands.trigger_targets(
|
let over_event = Pointer::new(
|
||||||
Pointer::new(pointer_id, location.clone(), Over { hit: hit.clone() }),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
Over { hit: hit.clone() },
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(over_event.clone(), hovered_entity);
|
||||||
|
event_writers.over_events.send(over_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +408,8 @@ pub fn pointer_events(
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
|
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
|
||||||
{
|
{
|
||||||
let event = Pointer::new(
|
let down_event = Pointer::new(
|
||||||
|
hovered_entity,
|
||||||
pointer_id,
|
pointer_id,
|
||||||
location.clone(),
|
location.clone(),
|
||||||
Down {
|
Down {
|
||||||
|
@ -389,7 +417,8 @@ pub fn pointer_events(
|
||||||
hit: hit.clone(),
|
hit: hit.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
commands.trigger_targets(event, hovered_entity);
|
commands.trigger_targets(down_event.clone(), hovered_entity);
|
||||||
|
event_writers.down_events.send(down_event);
|
||||||
// Also insert the press into the state
|
// Also insert the press into the state
|
||||||
state
|
state
|
||||||
.pressing
|
.pressing
|
||||||
|
@ -406,76 +435,76 @@ pub fn pointer_events(
|
||||||
// If this pointer previously pressed the hovered entity, emit a Click event
|
// If this pointer previously pressed the hovered entity, emit a Click event
|
||||||
if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity)
|
if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity)
|
||||||
{
|
{
|
||||||
commands.trigger_targets(
|
let click_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
Click {
|
|
||||||
button,
|
|
||||||
hit: hit.clone(),
|
|
||||||
duration: now - *press_instant,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
);
|
|
||||||
}
|
|
||||||
// Always send the Up event
|
|
||||||
commands.trigger_targets(
|
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
pointer_id,
|
||||||
location.clone(),
|
location.clone(),
|
||||||
Up {
|
Click {
|
||||||
button,
|
button,
|
||||||
hit: hit.clone(),
|
hit: hit.clone(),
|
||||||
|
duration: now - *press_instant,
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
commands.trigger_targets(click_event.clone(), hovered_entity);
|
||||||
|
event_writers.click_events.send(click_event);
|
||||||
|
}
|
||||||
|
// Always send the Up event
|
||||||
|
let up_event = Pointer::new(
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
Up {
|
||||||
|
button,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(up_event.clone(), hovered_entity);
|
||||||
|
event_writers.up_events.send(up_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then emit the drop events.
|
// Then emit the drop events.
|
||||||
for (drag_target, drag) in state.dragging.drain() {
|
for (drag_target, drag) in state.dragging.drain() {
|
||||||
// Emit DragDrop
|
// Emit DragDrop
|
||||||
for (dragged_over, hit) in state.dragging_over.iter() {
|
for (dragged_over, hit) in state.dragging_over.iter() {
|
||||||
commands.trigger_targets(
|
let drag_drop_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragDrop {
|
|
||||||
button,
|
|
||||||
dropped: drag_target,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
*dragged_over,
|
*dragged_over,
|
||||||
);
|
|
||||||
}
|
|
||||||
// Emit DragEnd
|
|
||||||
commands.trigger_targets(
|
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
pointer_id,
|
||||||
location.clone(),
|
location.clone(),
|
||||||
DragEnd {
|
DragDrop {
|
||||||
button,
|
button,
|
||||||
distance: drag.latest_pos - drag.start_pos,
|
dropped: drag_target,
|
||||||
|
hit: hit.clone(),
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
commands.trigger_targets(drag_drop_event.clone(), *dragged_over);
|
||||||
|
event_writers.drag_drop_events.send(drag_drop_event);
|
||||||
|
}
|
||||||
|
// Emit DragEnd
|
||||||
|
let drag_end_event = Pointer::new(
|
||||||
drag_target,
|
drag_target,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragEnd {
|
||||||
|
button,
|
||||||
|
distance: drag.latest_pos - drag.start_pos,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_end_event.clone(), drag_target);
|
||||||
|
event_writers.drag_end_events.send(drag_end_event);
|
||||||
// Emit DragLeave
|
// Emit DragLeave
|
||||||
for (dragged_over, hit) in state.dragging_over.iter() {
|
for (dragged_over, hit) in state.dragging_over.iter() {
|
||||||
commands.trigger_targets(
|
let drag_leave_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragLeave {
|
|
||||||
button,
|
|
||||||
dragged: drag_target,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
*dragged_over,
|
*dragged_over,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragLeave {
|
||||||
|
button,
|
||||||
|
dragged: drag_target,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_leave_event.clone(), *dragged_over);
|
||||||
|
event_writers.drag_leave_events.send(drag_leave_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,29 +533,36 @@ pub fn pointer_events(
|
||||||
latest_pos: location.position,
|
latest_pos: location.position,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
commands.trigger_targets(
|
let drag_start_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragStart {
|
|
||||||
button,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
*press_target,
|
*press_target,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragStart {
|
||||||
|
button,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_start_event.clone(), *press_target);
|
||||||
|
event_writers.drag_start_events.send(drag_start_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit Drag events to the entities we are dragging
|
// Emit Drag events to the entities we are dragging
|
||||||
for (drag_target, drag) in state.dragging.iter_mut() {
|
for (drag_target, drag) in state.dragging.iter_mut() {
|
||||||
let drag_event = Drag {
|
let drag_event = Pointer::new(
|
||||||
button,
|
*drag_target,
|
||||||
distance: location.position - drag.start_pos,
|
pointer_id,
|
||||||
delta: location.position - drag.latest_pos,
|
location.clone(),
|
||||||
};
|
Drag {
|
||||||
|
button,
|
||||||
|
distance: location.position - drag.start_pos,
|
||||||
|
delta: location.position - drag.latest_pos,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
commands.trigger_targets(drag_event.clone(), *drag_target);
|
||||||
|
event_writers.drag_events.send(drag_event);
|
||||||
|
|
||||||
|
// Update drag position
|
||||||
drag.latest_pos = location.position;
|
drag.latest_pos = location.position;
|
||||||
let event = Pointer::new(pointer_id, location.clone(), drag_event);
|
|
||||||
commands.trigger_targets(event, *drag_target);
|
|
||||||
|
|
||||||
// Emit corresponding DragOver to the hovered entities
|
// Emit corresponding DragOver to the hovered entities
|
||||||
for (hovered_entity, hit) in hover_map
|
for (hovered_entity, hit) in hover_map
|
||||||
|
@ -535,18 +571,18 @@ pub fn pointer_events(
|
||||||
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
||||||
.filter(|(hovered_entity, _)| *hovered_entity != *drag_target)
|
.filter(|(hovered_entity, _)| *hovered_entity != *drag_target)
|
||||||
{
|
{
|
||||||
commands.trigger_targets(
|
let drag_over_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragOver {
|
|
||||||
button,
|
|
||||||
dragged: *drag_target,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragOver {
|
||||||
|
button,
|
||||||
|
dragged: *drag_target,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_over_event.clone(), hovered_entity);
|
||||||
|
event_writers.drag_over_events.send(drag_over_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,17 +593,17 @@ pub fn pointer_events(
|
||||||
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
||||||
{
|
{
|
||||||
// Emit Move events to the entities we are hovering
|
// Emit Move events to the entities we are hovering
|
||||||
commands.trigger_targets(
|
let move_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
Move {
|
|
||||||
hit: hit.clone(),
|
|
||||||
delta,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
Move {
|
||||||
|
hit: hit.clone(),
|
||||||
|
delta,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(move_event.clone(), hovered_entity);
|
||||||
|
event_writers.move_events.send(move_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Canceled
|
// Canceled
|
||||||
|
@ -578,10 +614,10 @@ pub fn pointer_events(
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.to_owned())))
|
||||||
{
|
{
|
||||||
commands.trigger_targets(
|
let cancel_event =
|
||||||
Pointer::new(pointer_id, location.clone(), Cancel { hit }),
|
Pointer::new(hovered_entity, pointer_id, location.clone(), Cancel { hit });
|
||||||
hovered_entity,
|
commands.trigger_targets(cancel_event.clone(), hovered_entity);
|
||||||
);
|
event_writers.cancel_events.send(cancel_event);
|
||||||
}
|
}
|
||||||
// Clear the local state for the canceled pointer
|
// Clear the local state for the canceled pointer
|
||||||
for button in PointerButton::iter() {
|
for button in PointerButton::iter() {
|
||||||
|
@ -615,28 +651,32 @@ pub fn pointer_events(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Always send Out events
|
// Always send Out events
|
||||||
commands.trigger_targets(
|
let out_event = Pointer::new(
|
||||||
Pointer::new(pointer_id, location.clone(), Out { hit: hit.clone() }),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
Out { hit: hit.clone() },
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(out_event.clone(), hovered_entity);
|
||||||
|
event_writers.out_events.send(out_event);
|
||||||
|
|
||||||
// Possibly send DragLeave events
|
// Possibly send DragLeave events
|
||||||
for button in PointerButton::iter() {
|
for button in PointerButton::iter() {
|
||||||
let state = pointer_state.entry((pointer_id, button)).or_default();
|
let state = pointer_state.entry((pointer_id, button)).or_default();
|
||||||
state.dragging_over.remove(&hovered_entity);
|
state.dragging_over.remove(&hovered_entity);
|
||||||
for drag_target in state.dragging.keys() {
|
for drag_target in state.dragging.keys() {
|
||||||
commands.trigger_targets(
|
let drag_leave_event = Pointer::new(
|
||||||
Pointer::new(
|
|
||||||
pointer_id,
|
|
||||||
location.clone(),
|
|
||||||
DragLeave {
|
|
||||||
button,
|
|
||||||
dragged: *drag_target,
|
|
||||||
hit: hit.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
hovered_entity,
|
hovered_entity,
|
||||||
|
pointer_id,
|
||||||
|
location.clone(),
|
||||||
|
DragLeave {
|
||||||
|
button,
|
||||||
|
dragged: *drag_target,
|
||||||
|
hit: hit.clone(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
commands.trigger_targets(drag_leave_event.clone(), hovered_entity);
|
||||||
|
event_writers.drag_leave_events.send(drag_leave_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,6 +381,20 @@ impl Plugin for InteractionPlugin {
|
||||||
|
|
||||||
app.init_resource::<focus::HoverMap>()
|
app.init_resource::<focus::HoverMap>()
|
||||||
.init_resource::<focus::PreviousHoverMap>()
|
.init_resource::<focus::PreviousHoverMap>()
|
||||||
|
.add_event::<Pointer<Cancel>>()
|
||||||
|
.add_event::<Pointer<Click>>()
|
||||||
|
.add_event::<Pointer<Down>>()
|
||||||
|
.add_event::<Pointer<DragDrop>>()
|
||||||
|
.add_event::<Pointer<DragEnd>>()
|
||||||
|
.add_event::<Pointer<DragEnter>>()
|
||||||
|
.add_event::<Pointer<Drag>>()
|
||||||
|
.add_event::<Pointer<DragLeave>>()
|
||||||
|
.add_event::<Pointer<DragOver>>()
|
||||||
|
.add_event::<Pointer<DragStart>>()
|
||||||
|
.add_event::<Pointer<Move>>()
|
||||||
|
.add_event::<Pointer<Out>>()
|
||||||
|
.add_event::<Pointer<Over>>()
|
||||||
|
.add_event::<Pointer<Up>>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
(update_focus, pointer_events, update_interactions)
|
(update_focus, pointer_events, update_interactions)
|
||||||
|
|
Loading…
Reference in a new issue