Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4129,6 +4129,18 @@ description = "Demonstrates picking debug overlay"
category = "Picking"
wasm = true

[[example]]
name = "parent_picking"
path = "examples/picking/parent_picking.rs"
doc-scrape-examples = true
required-features = ["bevy_mesh_picking_backend"]

[package.metadata.example.parent_picking]
name = "Parent Picking"
description = "Demonstrates parent picking meshes"
category = "Picking"
wasm = true

[[example]]
name = "animation_masks"
path = "examples/animation/animation_masks.rs"
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_picking/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use crate::{
#[reflect(Component, Debug, Clone)]
pub struct Pointer<E: Debug + Clone + Reflect> {
/// The original target of this picking event, before bubbling
pub target: Entity,
pub original_target: Entity,
/// The pointer that triggered this event
pub pointer_id: PointerId,
/// The location of the pointer during this event
Expand Down Expand Up @@ -136,7 +136,7 @@ impl<E: Debug + Clone + Reflect> Pointer<E> {
/// Construct a new `Pointer<E>` event.
pub fn new(id: PointerId, location: Location, target: Entity, event: E) -> Self {
Self {
target,
original_target: target,
pointer_id: id,
pointer_location: location,
event,
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ Example | Description
Example | Description
--- | ---
[Mesh Picking](../examples/picking/mesh_picking.rs) | Demonstrates picking meshes
[Parent Picking](../examples/picking/parent_picking.rs) | Demonstrates parent picking meshes
[Picking Debug Tools](../examples/picking/debug_picking.rs) | Demonstrates picking debug overlay
[Showcases simple picking events and usage](../examples/picking/simple_picking.rs) | Demonstrates how to use picking events to spawn simple objects
[Sprite Picking](../examples/picking/sprite_picking.rs) | Demonstrates picking sprites and sprite atlases
Expand Down
2 changes: 1 addition & 1 deletion examples/ecs/error_handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ fn fallible_observer(
mut step: Local<f32>,
) -> Result {
let mut transform = world
.get_mut::<Transform>(trigger.target)
.get_mut::<Transform>(trigger.target())
.ok_or("No transform found.")?;

*step = if transform.translation.x > 3. {
Expand Down
93 changes: 93 additions & 0 deletions examples/picking/parent_picking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//! A simple 3D scene to demonstrate parent picking.
//!
//! Entity hierarchies can be built using a [`ChildOf`] component. By observing for
//! [`Trigger<Pointer<E>>`] events on the parent entity, picking events can be collected
//! for the entire tree, giving both the leaf and root nodes selected.

use bevy::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(MeshPickingPlugin)
.add_systems(Startup, setup)
.add_systems(PreUpdate, close_on_esc)
.run();
}

/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let parent_id = commands
.spawn((
Name::new("Parent"),
Transform::IDENTITY,
Visibility::Visible,
))
.observe(on_pointer_over_debug)
.id();

// circular base
commands.spawn((
Name::new("Base"),
Mesh3d(meshes.add(Circle::new(4.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
ChildOf(parent_id),
));

// cube
commands.spawn((
Name::new("Cube"),
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
Transform::from_xyz(0.0, 0.5, 0.0),
ChildOf(parent_id),
));

// light
commands.spawn((
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
));

// camera
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}

fn on_pointer_over_debug(trigger: Trigger<Pointer<Over>>, query: Query<&Name>) {
if let Ok(name) = query.get(trigger.target()) {
println!("root = trigger.target() = {:?}", name);
}

// NOTE: trigger.original_target = trigger.event().original_target
// this is due to [`impl Deref for Pointer`]
if let Ok(name) = query.get(trigger.original_target) {
println!("leaf = trigger.original_target = {:?}", name);
}
}

fn close_on_esc(
mut commands: Commands,
focused_windows: Query<(Entity, &Window)>,
input: Res<ButtonInput<KeyCode>>,
) {
for (window, focus) in focused_windows.iter() {
if !focus.focused {
continue;
}

if input.just_pressed(KeyCode::Escape) {
commands.entity(window).despawn();
}
}
}
2 changes: 1 addition & 1 deletion examples/ui/directional_navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ fn interact_with_focused_button(
if let Some(focused_entity) = input_focus.0 {
commands.trigger_targets(
Pointer::<Click> {
target: focused_entity,
original_target: focused_entity,
// We're pretending that we're a mouse
pointer_id: PointerId::Mouse,
// This field isn't used, so we're just setting it to a placeholder value
Expand Down
10 changes: 10 additions & 0 deletions release-content/migration-guides/parent_picking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Parent Picking
pull_requests: [18982]
---

`target` on `Trigger<Pointer<E>>` has been renamed to `original_target`.

Previously `.target()` and `.target` would refer to two separate entities, the root and the leaf of the entity hierarchy.

See `examples/picking/parent_picking.rs` for a demonstration of this.