bevy/crates/bevy_picking/src/lib.rs
Joona Aalto 38c3423693
Event Split: Event, EntityEvent, and BufferedEvent (#19647)
# Objective

Closes #19564.

The current `Event` trait looks like this:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The `Event` trait is used by both buffered events
(`EventReader`/`EventWriter`) and observer events. If they are observer
events, they can optionally be targeted at specific `Entity`s or
`ComponentId`s, and can even be propagated to other entities.

However, there has long been a desire to split the trait semantically
for a variety of reasons, see #14843, #14272, and #16031 for discussion.
Some reasons include:

- It's very uncommon to use a single event type as both a buffered event
and targeted observer event. They are used differently and tend to have
distinct semantics.
- A common footgun is using buffered events with observers or event
readers with observer events, as there is no type-level error that
prevents this kind of misuse.
- #19440 made `Trigger::target` return an `Option<Entity>`. This
*seriously* hurts ergonomics for the general case of entity observers,
as you need to `.unwrap()` each time. If we could statically determine
whether the event is expected to have an entity target, this would be
unnecessary.

There's really two main ways that we can categorize events: push vs.
pull (i.e. "observer event" vs. "buffered event") and global vs.
targeted:

|              | Push            | Pull                        |
| ------------ | --------------- | --------------------------- |
| **Global**   | Global observer | `EventReader`/`EventWriter` |
| **Targeted** | Entity observer | -                           |

There are many ways to approach this, each with their tradeoffs.
Ultimately, we kind of want to split events both ways:

- A type-level distinction between observer events and buffered events,
to prevent people from using the wrong kind of event in APIs
- A statically designated entity target for observer events to avoid
accidentally using untargeted events for targeted APIs

This PR achieves these goals by splitting event traits into `Event`,
`EntityEvent`, and `BufferedEvent`, with `Event` being the shared trait
implemented by all events.

## `Event`, `EntityEvent`, and `BufferedEvent`

`Event` is now a very simple trait shared by all events.

```rust
pub trait Event: Send + Sync + 'static {
    // Required for observer APIs
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

You can call `trigger` for *any* event, and use a global observer for
listening to the event.

```rust
#[derive(Event)]
struct Speak {
    message: String,
}

// ...

app.add_observer(|trigger: On<Speak>| {
    println!("{}", trigger.message);
});

// ...

commands.trigger(Speak {
    message: "Y'all like these reworked events?".to_string(),
});
```

To allow an event to be targeted at entities and even propagated
further, you can additionally implement the `EntityEvent` trait:

```rust
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This lets you call `trigger_targets`, and to use targeted observer APIs
like `EntityCommands::observe`:

```rust
#[derive(Event, EntityEvent)]
#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct Damage {
    amount: f32,
}

// ...

let enemy = commands.spawn((Enemy, Health(100.0))).id();

// Spawn some armor as a child of the enemy entity.
// When the armor takes damage, it will bubble the event up to the enemy.
let armor_piece = commands
    .spawn((ArmorPiece, Health(25.0), ChildOf(enemy)))
    .observe(|trigger: On<Damage>, mut query: Query<&mut Health>| {
        // Note: `On::target` only exists because this is an `EntityEvent`.
        let mut health = query.get(trigger.target()).unwrap();
        health.0 -= trigger.amount();
    });

commands.trigger_targets(Damage { amount: 10.0 }, armor_piece);
```

> [!NOTE]
> You *can* still also trigger an `EntityEvent` without targets using
`trigger`. We probably *could* make this an either-or thing, but I'm not
sure that's actually desirable.

To allow an event to be used with the buffered API, you can implement
`BufferedEvent`:

```rust
pub trait BufferedEvent: Event {}
```

The event can then be used with `EventReader`/`EventWriter`:

```rust
#[derive(Event, BufferedEvent)]
struct Message(String);

fn write_hello(mut writer: EventWriter<Message>) {
    writer.write(Message("I hope these examples are alright".to_string()));
}

fn read_messages(mut reader: EventReader<Message>) {
    // Process all buffered events of type `Message`.
    for Message(message) in reader.read() {
        println!("{message}");
    }
}
```

In summary:

- Need a basic event you can trigger and observe? Derive `Event`!
- Need the event to be targeted at an entity? Derive `EntityEvent`!
- Need the event to be buffered and support the
`EventReader`/`EventWriter` API? Derive `BufferedEvent`!

## Alternatives

I'll now cover some of the alternative approaches I have considered and
briefly explored. I made this section collapsible since it ended up
being quite long :P

<details>

<summary>Expand this to see alternatives</summary>

### 1. Unified `Event` Trait

One option is not to have *three* separate traits (`Event`,
`EntityEvent`, `BufferedEvent`), and to instead just use associated
constants on `Event` to determine whether an event supports targeting
and buffering or not:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    const BUFFERED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

Methods can then use bounds like `where E: Event<TARGETED = true>` or
`where E: Event<BUFFERED = true>` to limit APIs to specific kinds of
events.

This would keep everything under one `Event` trait, but I don't think
it's necessarily a good idea. It makes APIs harder to read, and docs
can't easily refer to specific types of events. You can also create
weird invariants: what if you specify `TARGETED = false`, but have
`Traversal` and/or `AUTO_PROPAGATE` enabled?

### 2. `Event` and `Trigger`

Another option is to only split the traits between buffered events and
observer events, since that is the main thing people have been asking
for, and they have the largest API difference.

If we did this, I think we would need to make the terms *clearly*
separate. We can't really use `Event` and `BufferedEvent` as the names,
since it would be strange that `BufferedEvent` doesn't implement
`Event`. Something like `ObserverEvent` and `BufferedEvent` could work,
but it'd be more verbose.

For this approach, I would instead keep `Event` for the current
`EventReader`/`EventWriter` API, and call the observer event a
`Trigger`, since the "trigger" terminology is already used in the
observer context within Bevy (both as a noun and a verb). This is also
what a long [bikeshed on
Discord](https://discord.com/channels/691052431525675048/749335865876021248/1298057661878898791)
seemed to land on at the end of last year.

```rust
// For `EventReader`/`EventWriter`
pub trait Event: Send + Sync + 'static {}

// For observers
pub trait Trigger: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The problem is that "event" is just a really good term for something
that "happens". Observers are rapidly becoming the more prominent API,
so it'd be weird to give them the `Trigger` name and leave the good
`Event` name for the less common API.

So, even though a split like this seems neat on the surface, I think it
ultimately wouldn't really work. We want to keep the `Event` name for
observer events, and there is no good alternative for the buffered
variant. (`Message` was suggested, but saying stuff like "sends a
collision message" is weird.)

### 3. `GlobalEvent` + `TargetedEvent`

What if instead of focusing on the buffered vs. observed split, we
*only* make a distinction between global and targeted events?

```rust
// A shared event trait to allow global observers to work
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For buffered events and non-targeted observer events
pub trait GlobalEvent: Event {}

// For targeted observer events
pub trait TargetedEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is actually the first approach I implemented, and it has the neat
characteristic that you can only use non-targeted APIs like `trigger`
with a `GlobalEvent` and targeted APIs like `trigger_targets` with a
`TargetedEvent`. You have full control over whether the entity should or
should not have a target, as they are fully distinct at the type-level.

However, there's a few problems:

- There is no type-level indication of whether a `GlobalEvent` supports
buffered events or just non-targeted observer events
- An `Event` on its own does literally nothing, it's just a shared trait
required to make global observers accept both non-targeted and targeted
events
- If an event is both a `GlobalEvent` and `TargetedEvent`, global
observers again have ambiguity on whether an event has a target or not,
undermining some of the benefits
- The names are not ideal

### 4. `Event` and `EntityEvent`

We can fix some of the problems of Alternative 3 by accepting that
targeted events can also be used in non-targeted contexts, and simply
having the `Event` and `EntityEvent` traits:

```rust
// For buffered events and non-targeted observer events
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For targeted observer events
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is essentially identical to this PR, just without a dedicated
`BufferedEvent`. The remaining major "problem" is that there is still
zero type-level indication of whether an `Event` event *actually*
supports the buffered API. This leads us to the solution proposed in
this PR, using `Event`, `EntityEvent`, and `BufferedEvent`.

</details>

## Conclusion

The `Event` + `EntityEvent` + `BufferedEvent` split proposed in this PR
aims to solve all the common problems with Bevy's current event model
while keeping the "weirdness" factor minimal. It splits in terms of both
the push vs. pull *and* global vs. targeted aspects, while maintaining a
shared concept for an "event".

### Why I Like This

- The term "event" remains as a single concept for all the different
kinds of events in Bevy.
- Despite all event types being "events", they use fundamentally
different APIs. Instead of assuming that you can use an event type with
any pattern (when only one is typically supported), you explicitly opt
in to each one with dedicated traits.
- Using separate traits for each type of event helps with documentation
and clearer function signatures.
- I can safely make assumptions on expected usage.
- If I see that an event is an `EntityEvent`, I can assume that I can
use `observe` on it and get targeted events.
- If I see that an event is a `BufferedEvent`, I can assume that I can
use `EventReader` to read events.
- If I see both `EntityEvent` and `BufferedEvent`, I can assume that
both APIs are supported.

In summary: This allows for a unified concept for events, while limiting
the different ways to use them with opt-in traits. No more guess-work
involved when using APIs.

### Problems?

- Because `BufferedEvent` implements `Event` (for more consistent
semantics etc.), you can still use all buffered events for non-targeted
observers. I think this is fine/good. The important part is that if you
see that an event implements `BufferedEvent`, you know that the
`EventReader`/`EventWriter` API should be supported. Whether it *also*
supports other APIs is secondary.
- I currently only support `trigger_targets` for an `EntityEvent`.
However, you can technically target components too, without targeting
any entities. I consider that such a niche and advanced use case that
it's not a huge problem to only support it for `EntityEvent`s, but we
could also split `trigger_targets` into `trigger_entities` and
`trigger_components` if we wanted to (or implement components as
entities :P).
- You can still trigger an `EntityEvent` *without* targets. I consider
this correct, since `Event` implements the non-targeted behavior, and
it'd be weird if implementing another trait *removed* behavior. However,
it does mean that global observers for entity events can technically
return `Entity::PLACEHOLDER` again (since I got rid of the
`Option<Entity>` added in #19440 for ergonomics). I think that's enough
of an edge case that it's not a huge problem, but it is worth keeping in
mind.
- ~~Deriving both `EntityEvent` and `BufferedEvent` for the same type
currently duplicates the `Event` implementation, so you instead need to
manually implement one of them.~~ Changed to always requiring `Event` to
be derived.

## Related Work

There are plans to implement multi-event support for observers,
especially for UI contexts. [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)
API looked like this:

```rust
// Truncated for brevity
trigger: Trigger<(
    OnAdd<Pressed>,
    OnRemove<Pressed>,
    OnAdd<InteractionDisabled>,
    OnRemove<InteractionDisabled>,
    OnInsert<Hovered>,
)>,
```

I believe this shouldn't be in conflict with this PR. If anything, this
PR might *help* achieve the multi-event pattern for entity observers
with fewer footguns: by statically enforcing that all of these events
are `EntityEvent`s in the context of `EntityCommands::observe`, we can
avoid misuse or weird cases where *some* events inside the trigger are
targeted while others are not.
2025-06-15 16:46:34 +00:00

445 lines
19 KiB
Rust

//! This crate provides 'picking' capabilities for the Bevy game engine, allowing pointers to
//! interact with entities using hover, click, and drag events.
//!
//! ## Overview
//!
//! In the simplest case, this plugin allows you to click on things in the scene. However, it also
//! allows you to express more complex interactions, like detecting when a touch input drags a UI
//! element and drops it on a 3d mesh rendered to a different camera.
//!
//! Pointer events bubble up the entity hierarchy and can be used with observers, allowing you to
//! succinctly express rich interaction behaviors by attaching pointer callbacks to entities:
//!
//! ```rust
//! # use bevy_ecs::prelude::*;
//! # use bevy_picking::prelude::*;
//! # #[derive(Component)]
//! # struct MyComponent;
//! # let mut world = World::new();
//! world.spawn(MyComponent)
//! .observe(|mut trigger: On<Pointer<Click>>| {
//! println!("I was just clicked!");
//! // Get the underlying pointer event data
//! let click_event: &Pointer<Click> = trigger.event();
//! // Stop the event from bubbling up the entity hierarchy
//! trigger.propagate(false);
//! });
//! ```
//!
//! At its core, this crate provides a robust abstraction for computing picking state regardless of
//! pointing devices, or what you are hit testing against. It is designed to work with any input,
//! including mouse, touch, pens, or virtual pointers controlled by gamepads.
//!
//! ## Expressive Events
//!
//! Although the events in this module (see [`events`]) can be listened to with normal
//! `EventReader`s, using observers is often more expressive, with less boilerplate. This is because
//! observers allow you to attach event handling logic to specific entities, as well as make use of
//! event bubbling.
//!
//! When events are generated, they bubble up the entity hierarchy starting from their target, until
//! they reach the root or bubbling is halted with a call to
//! [`On::propagate`](bevy_ecs::observer::On::propagate). See [`Observer`] for details.
//!
//! This allows you to run callbacks when any children of an entity are interacted with, and leads
//! to succinct, expressive code:
//!
//! ```
//! # use bevy_ecs::prelude::*;
//! # use bevy_transform::prelude::*;
//! # use bevy_picking::prelude::*;
//! # #[derive(Event, BufferedEvent)]
//! # struct Greeting;
//! fn setup(mut commands: Commands) {
//! commands.spawn(Transform::default())
//! // Spawn your entity here, e.g. a `Mesh3d`.
//! // When dragged, mutate the `Transform` component on the dragged target entity:
//! .observe(|trigger: On<Pointer<Drag>>, mut transforms: Query<&mut Transform>| {
//! let mut transform = transforms.get_mut(trigger.target()).unwrap();
//! let drag = trigger.event();
//! transform.rotate_local_y(drag.delta.x / 50.0);
//! })
//! .observe(|trigger: On<Pointer<Click>>, mut commands: Commands| {
//! println!("Entity {} goes BOOM!", trigger.target());
//! commands.entity(trigger.target()).despawn();
//! })
//! .observe(|trigger: On<Pointer<Over>>, mut events: EventWriter<Greeting>| {
//! events.write(Greeting);
//! });
//! }
//! ```
//!
//! ## Modularity
//!
//! #### Mix and Match Hit Testing Backends
//!
//! The plugin attempts to handle all the hard parts for you, all you need to do is tell it when a
//! pointer is hitting any entities. Multiple backends can be used at the same time! [Use this
//! simple API to write your own backend](crate::backend) in about 100 lines of code.
//!
//! #### Input Agnostic
//!
//! Picking provides a generic Pointer abstraction, which is useful for reacting to many different
//! types of input devices. Pointers can be controlled with anything, whether it's the included
//! mouse or touch inputs, or a custom gamepad input system you write yourself to control a virtual
//! pointer.
//!
//! ## Robustness
//!
//! In addition to these features, this plugin also correctly handles multitouch, multiple windows,
//! multiple cameras, viewports, and render layers. Using this as a library allows you to write a
//! picking backend that can interoperate with any other picking backend.
//!
//! # Getting Started
//!
//! TODO: This section will need to be re-written once more backends are introduced.
//!
//! #### Next Steps
//!
//! To learn more, take a look at the examples in the
//! [examples](https://github.com/bevyengine/bevy/tree/main/examples/picking). You can read the next
//! section to understand how the plugin works.
//!
//! # The Picking Pipeline
//!
//! This plugin is designed to be extremely modular. To do so, it works in well-defined stages that
//! form a pipeline, where events are used to pass data between each stage.
//!
//! #### Pointers ([`pointer`](mod@pointer))
//!
//! The first stage of the pipeline is to gather inputs and update pointers. This stage is
//! ultimately responsible for generating [`PointerInput`](pointer::PointerInput) events. The
//! provided crate does this automatically for mouse, touch, and pen inputs. If you wanted to
//! implement your own pointer, controlled by some other input, you can do that here. The ordering
//! of events within the [`PointerInput`](pointer::PointerInput) stream is meaningful for events
//! with the same [`PointerId`](pointer::PointerId), but not between different pointers.
//!
//! Because pointer positions and presses are driven by these events, you can use them to mock
//! inputs for testing.
//!
//! After inputs are generated, they are then collected to update the current
//! [`PointerLocation`](pointer::PointerLocation) for each pointer.
//!
//! #### Backend ([`backend`])
//!
//! A picking backend only has one job: reading [`PointerLocation`](pointer::PointerLocation)
//! components, and producing [`PointerHits`](backend::PointerHits). You can find all documentation
//! and types needed to implement a backend at [`backend`].
//!
//! You will eventually need to choose which picking backend(s) you want to use. This crate does not
//! supply any backends, and expects you to select some from the other bevy crates or the
//! third-party ecosystem.
//!
//! It's important to understand that you can mix and match backends! For example, you might have a
//! backend for your UI, and one for the 3d scene, with each being specialized for their purpose.
//! Bevy provides some backends out of the box, but you can even write your own. It's been made as
//! easy as possible intentionally; the `bevy_mod_raycast` backend is 50 lines of code.
//!
//! #### Hover ([`hover`])
//!
//! The next step is to use the data from the backends, combine and sort the results, and determine
//! what each cursor is hovering over, producing a [`HoverMap`](`crate::hover::HoverMap`). Note that
//! just because a pointer is over an entity, it is not necessarily *hovering* that entity. Although
//! multiple backends may be reporting that a pointer is hitting an entity, the hover system needs
//! to determine which entities are actually being hovered by this pointer based on the pick depth,
//! order of the backend, and the optional [`Pickable`] component of the entity. In other
//! words, if one entity is in front of another, usually only the topmost one will be hovered.
//!
//! #### Events ([`events`])
//!
//! In the final step, the high-level pointer events are generated, such as events that trigger when
//! a pointer hovers or clicks an entity. These simple events are then used to generate more complex
//! events for dragging and dropping.
//!
//! Because it is completely agnostic to the earlier stages of the pipeline, you can easily extend
//! the plugin with arbitrary backends and input methods, yet still use all the high level features.
#![deny(missing_docs)]
extern crate alloc;
pub mod backend;
pub mod events;
pub mod hover;
pub mod input;
#[cfg(feature = "bevy_mesh_picking_backend")]
pub mod mesh_picking;
pub mod pointer;
pub mod window;
use bevy_app::{prelude::*, PluginGroupBuilder};
use bevy_ecs::prelude::*;
use bevy_reflect::prelude::*;
use hover::{update_is_directly_hovered, update_is_hovered};
/// The picking prelude.
///
/// This includes the most common types in this crate, re-exported for your convenience.
pub mod prelude {
#[cfg(feature = "bevy_mesh_picking_backend")]
#[doc(hidden)]
pub use crate::mesh_picking::{
ray_cast::{MeshRayCast, MeshRayCastSettings, RayCastBackfaces, RayCastVisibility},
MeshPickingCamera, MeshPickingPlugin, MeshPickingSettings,
};
#[doc(hidden)]
pub use crate::{
events::*, input::PointerInputPlugin, pointer::PointerButton, DefaultPickingPlugins,
InteractionPlugin, Pickable, PickingPlugin,
};
}
/// An optional component that marks an entity as usable by a backend, and overrides default
/// picking behavior for an entity.
///
/// This allows you to make an entity non-hoverable, or allow items below it to be hovered.
///
/// See the documentation on the fields for more details.
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
#[reflect(Component, Default, Debug, PartialEq, Clone)]
pub struct Pickable {
/// Should this entity block entities below it from being picked?
///
/// This is useful if you want picking to continue hitting entities below this one. Normally,
/// only the topmost entity under a pointer can be hovered, but this setting allows the pointer
/// to hover multiple entities, from nearest to farthest, stopping as soon as it hits an entity
/// that blocks lower entities.
///
/// Note that the word "lower" here refers to entities that have been reported as hit by any
/// picking backend, but are at a lower depth than the current one. This is different from the
/// concept of event bubbling, as it works irrespective of the entity hierarchy.
///
/// For example, if a pointer is over a UI element, as well as a 3d mesh, backends will report
/// hits for both of these entities. Additionally, the hits will be sorted by the camera order,
/// so if the UI is drawing on top of the 3d mesh, the UI will be "above" the mesh. When hovering
/// is computed, the UI element will be checked first to see if it this field is set to block
/// lower entities. If it does (default), the hovering system will stop there, and only the UI
/// element will be marked as hovered. However, if this field is set to `false`, both the UI
/// element *and* the mesh will be marked as hovered.
///
/// Entities without the [`Pickable`] component will block by default.
pub should_block_lower: bool,
/// If this is set to `false` and `should_block_lower` is set to true, this entity will block
/// lower entities from being interacted and at the same time will itself not emit any events.
///
/// Note that the word "lower" here refers to entities that have been reported as hit by any
/// picking backend, but are at a lower depth than the current one. This is different from the
/// concept of event bubbling, as it works irrespective of the entity hierarchy.
///
/// For example, if a pointer is over a UI element, and this field is set to `false`, it will
/// not be marked as hovered, and consequently will not emit events nor will any picking
/// components mark it as hovered. This can be combined with the other field
/// [`Self::should_block_lower`], which is orthogonal to this one.
///
/// Entities without the [`Pickable`] component are hoverable by default.
pub is_hoverable: bool,
}
impl Pickable {
/// This entity will not block entities beneath it, nor will it emit events.
///
/// If a backend reports this entity as being hit, the picking plugin will completely ignore it.
pub const IGNORE: Self = Self {
should_block_lower: false,
is_hoverable: false,
};
}
impl Default for Pickable {
fn default() -> Self {
Self {
should_block_lower: true,
is_hoverable: true,
}
}
}
/// Groups the stages of the picking process under shared labels.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub enum PickingSystems {
/// Produces pointer input events. In the [`First`] schedule.
Input,
/// Runs after input events are generated but before commands are flushed. In the [`First`]
/// schedule.
PostInput,
/// Receives and processes pointer input events. In the [`PreUpdate`] schedule.
ProcessInput,
/// Reads inputs and produces [`backend::PointerHits`]s. In the [`PreUpdate`] schedule.
Backend,
/// Reads [`backend::PointerHits`]s, and updates the hovermap, selection, and highlighting states. In
/// the [`PreUpdate`] schedule.
Hover,
/// Runs after all the [`PickingSystems::Hover`] systems are done, before event listeners are triggered. In the
/// [`PreUpdate`] schedule.
PostHover,
/// Runs after all other picking sets. In the [`PreUpdate`] schedule.
Last,
}
/// Deprecated alias for [`PickingSystems`].
#[deprecated(since = "0.17.0", note = "Renamed to `PickingSystems`.")]
pub type PickSet = PickingSystems;
/// One plugin that contains the [`PointerInputPlugin`](input::PointerInputPlugin), [`PickingPlugin`]
/// and the [`InteractionPlugin`], this is probably the plugin that will be most used.
///
/// Note: for any of these plugins to work, they require a picking backend to be active,
/// The picking backend is responsible to turn an input, into a [`crate::backend::PointerHits`]
/// that [`PickingPlugin`] and [`InteractionPlugin`] will refine into [`bevy_ecs::observer::On`]s.
#[derive(Default)]
pub struct DefaultPickingPlugins;
impl PluginGroup for DefaultPickingPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(input::PointerInputPlugin::default())
.add(PickingPlugin::default())
.add(InteractionPlugin)
}
}
/// This plugin sets up the core picking infrastructure. It receives input events, and provides the shared
/// types used by other picking plugins.
///
/// This plugin contains several settings, and is added to the world as a resource after initialization. You
/// can configure picking settings at runtime through the resource.
#[derive(Copy, Clone, Debug, Resource, Reflect)]
#[reflect(Resource, Default, Debug, Clone)]
pub struct PickingPlugin {
/// Enables and disables all picking features.
pub is_enabled: bool,
/// Enables and disables input collection.
pub is_input_enabled: bool,
/// Enables and disables updating interaction states of entities.
pub is_hover_enabled: bool,
/// Enables or disables picking for window entities.
pub is_window_picking_enabled: bool,
}
impl PickingPlugin {
/// Whether or not input collection systems should be running.
pub fn input_should_run(state: Res<Self>) -> bool {
state.is_input_enabled && state.is_enabled
}
/// Whether or not systems updating entities' [`PickingInteraction`](hover::PickingInteraction)
/// component should be running.
pub fn hover_should_run(state: Res<Self>) -> bool {
state.is_hover_enabled && state.is_enabled
}
/// Whether or not window entities should receive pick events.
pub fn window_picking_should_run(state: Res<Self>) -> bool {
state.is_window_picking_enabled && state.is_enabled
}
}
impl Default for PickingPlugin {
fn default() -> Self {
Self {
is_enabled: true,
is_input_enabled: true,
is_hover_enabled: true,
is_window_picking_enabled: true,
}
}
}
impl Plugin for PickingPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(*self)
.init_resource::<pointer::PointerMap>()
.init_resource::<backend::ray::RayMap>()
.add_event::<pointer::PointerInput>()
.add_event::<backend::PointerHits>()
// Rather than try to mark all current and future backends as ambiguous with each other,
// we allow them to send their hits in any order. These are later sorted, so submission
// order doesn't matter. See `PointerHits` docs for caveats.
.allow_ambiguous_resource::<Events<backend::PointerHits>>()
.add_systems(
PreUpdate,
(
pointer::update_pointer_map,
pointer::PointerInput::receive,
backend::ray::RayMap::repopulate.after(pointer::PointerInput::receive),
)
.in_set(PickingSystems::ProcessInput),
)
.add_systems(
PreUpdate,
window::update_window_hits
.run_if(Self::window_picking_should_run)
.in_set(PickingSystems::Backend),
)
.configure_sets(
First,
(PickingSystems::Input, PickingSystems::PostInput)
.after(bevy_time::TimeSystems)
.after(bevy_ecs::event::EventUpdateSystems)
.chain(),
)
.configure_sets(
PreUpdate,
(
PickingSystems::ProcessInput.run_if(Self::input_should_run),
PickingSystems::Backend,
PickingSystems::Hover.run_if(Self::hover_should_run),
PickingSystems::PostHover,
PickingSystems::Last,
)
.chain(),
)
.register_type::<Self>()
.register_type::<Pickable>()
.register_type::<hover::PickingInteraction>()
.register_type::<hover::Hovered>()
.register_type::<pointer::PointerId>()
.register_type::<pointer::PointerLocation>()
.register_type::<pointer::PointerPress>()
.register_type::<pointer::PointerInteraction>()
.register_type::<backend::ray::RayId>();
}
}
/// Generates [`Pointer`](events::Pointer) events and handles event bubbling.
#[derive(Default)]
pub struct InteractionPlugin;
impl Plugin for InteractionPlugin {
fn build(&self, app: &mut App) {
use events::*;
use hover::{generate_hovermap, update_interactions};
app.init_resource::<hover::HoverMap>()
.init_resource::<hover::PreviousHoverMap>()
.init_resource::<PointerState>()
.add_event::<Pointer<Cancel>>()
.add_event::<Pointer<Click>>()
.add_event::<Pointer<Press>>()
.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<Release>>()
.add_event::<Pointer<Scroll>>()
.add_systems(
PreUpdate,
(
generate_hovermap,
update_interactions,
(update_is_hovered, update_is_directly_hovered),
pointer_events,
)
.chain()
.in_set(PickingSystems::Hover),
);
}
}